From 8bd24bfe7c66e72c0f25e31f158b3cc3a39657b0 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 24 Apr 2024 18:00:34 +0200 Subject: [PATCH 1/7] Introduced debug mode. --- .env.sample | 9 ++ dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/browser.js | 23 +++-- lib/envs.js | 11 ++- lib/pool.js | 9 ++ lib/schemas/config.js | 89 +++++++++++++++++++ lib/utils.js | 2 +- msg/startup.msg | 20 ++--- package-lock.json | 194 +++++++++++++++++++++--------------------- package.json | 9 +- 12 files changed, 249 insertions(+), 125 deletions(-) diff --git a/.env.sample b/.env.sample index 67575c94..eeb6b00a 100644 --- a/.env.sample +++ b/.env.sample @@ -71,3 +71,12 @@ UI_ROUTE = / OTHER_NODE_ENV = production OTHER_LISTEN_TO_PROCESS_EXITS = true OTHER_NO_LOGO = false + +# DEBUG CONFIG +DEBUG_ENABLE = false +DEBUG_HEADLESS = false +DEBUG_DEVTOOLS = false +DEBUG_LISTEN_TO_CONSOLE = false +DEBUG_DUMPIO = false +DEBUG_SLOW_MO = 0 +DEBUG_DEBUGGING_PORT = 9222 diff --git a/dist/index.cjs b/dist/index.cjs index f0695139..2048ac3b 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),h=require("node:path"),u=require("puppeteer"),d=require("node:crypto"),g=require("jsdom"),m=require("dompurify"),f=require("cors"),v=require("express"),y=require("multer"),w=require("express-rate-limit"),b="undefined"!=typeof document?document.currentScript:null;function E(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var T=E(n);const S={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},x={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:S.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:S.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:S.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},R={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:x.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:x.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:x.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:x.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:x.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:x.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${x.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${x.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:x.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:x.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:x.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:x.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:x.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:x.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:x.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:x.server.host.value},{type:"number",name:"port",message:"Server port",initial:x.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:x.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:x.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:x.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:x.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:x.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:x.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:x.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:x.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:x.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:x.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:x.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:x.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:x.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:x.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:x.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:x.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:x.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:x.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:x.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:x.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:x.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:x.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:x.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:x.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:x.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:x.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:x.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:x.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:x.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:x.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:x.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:x.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:x.other.noLogo.value}]},L=["options","globalOptions","themeOptions","resources","payload"],k={},_=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?_(i,`${t}.${r}`):(k[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(k[i.legacyName]=`${t}.${r}`.substring(1)))}}))};_(x),o.config();const O=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),I=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),C=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),A=()=>s.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),N=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),P=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=s.z.object({HIGHCHARTS_VERSION:s.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:s.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(S.core),HIGHCHARTS_MODULE_SCRIPTS:O(S.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(S.indicators),HIGHCHARTS_FORCE_FETCH:I(),HIGHCHARTS_CACHE_PATH:A(),HIGHCHARTS_ADMIN_TOKEN:A(),EXPORT_TYPE:C(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:C(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:N(),EXPORT_DEFAULT_WIDTH:N(),EXPORT_DEFAULT_SCALE:N(),EXPORT_RASTERIZATION_TIMEOUT:P(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:I(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:I(),SERVER_ENABLE:I(),SERVER_HOST:A(),SERVER_PORT:N(),SERVER_BENCHMARKING:I(),SERVER_PROXY_HOST:A(),SERVER_PROXY_PORT:N(),SERVER_PROXY_TIMEOUT:P(),SERVER_RATE_LIMITING_ENABLE:I(),SERVER_RATE_LIMITING_MAX_REQUESTS:P(),SERVER_RATE_LIMITING_WINDOW:P(),SERVER_RATE_LIMITING_DELAY:P(),SERVER_RATE_LIMITING_TRUST_PROXY:I(),SERVER_RATE_LIMITING_SKIP_KEY:A(),SERVER_RATE_LIMITING_SKIP_TOKEN:A(),SERVER_SSL_ENABLE:I(),SERVER_SSL_FORCE:I(),SERVER_SSL_PORT:N(),SERVER_SSL_CERT_PATH:A(),POOL_MIN_WORKERS:P(),POOL_MAX_WORKERS:P(),POOL_WORK_LIMIT:N(),POOL_ACQUIRE_TIMEOUT:P(),POOL_CREATE_TIMEOUT:P(),POOL_DESTROY_TIMEOUT:P(),POOL_IDLE_TIMEOUT:P(),POOL_CREATE_RETRY_INTERVAL:P(),POOL_REAPER_INTERVAL:P(),POOL_BENCHMARKING:I(),LOGGING_LEVEL:s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:A(),LOGGING_DEST:A(),UI_ENABLE:I(),UI_ROUTE:A(),OTHER_NODE_ENV:C(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:I(),OTHER_NO_LOGO:I()}).partial().parse(process.env),H=["red","yellow","blue","gray","green"];let j={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:H[0]},{title:"warning",color:H[1]},{title:"notice",color:H[2]},{title:"verbose",color:H[3]},{title:"benchmark",color:H[4]}],listeners:[]};for(const[e,t]of Object.entries(x.logging))j[e]=t.value;const U=(t,r)=>{j.toFile&&(j.pathCreated||(!e.existsSync(j.dest)&&e.mkdirSync(j.dest),j.pathCreated=!0),e.appendFile(`${j.dest}${j.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),j.toFile=!1)})))},F=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=j;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;j.listeners.forEach((e=>{e(s,r.join(" "))})),j.toConsole&&console.log.apply(void 0,[s.toString()[j.levelsDesc[t-1].color]].concat(r)),U(r,s)},G=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:s}=j;if(0===e||e>o||o>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];j.toConsole&&console.log.apply(void 0,[n.toString()[j.levelsDesc[e-1].color]].concat([i[H[e-1]],"\n",a])),j.listeners.forEach((e=>{e(n,l.join(" "))})),U(l,n)},M=e=>{e>=0&&e<=j.levelsDesc.length&&(j.level=e)},q=(e,t)=>{if(j={...j,dest:e||j.dest,file:t||j.file,toFile:!0},0===j.dest.length)return F(1,"[logger] File logging initialization: no path supplied.");j.dest.endsWith("/")||(j.dest+="/")},D=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:b&&b.src||new URL("index.cjs",document.baseURI).href)),V=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},W=(t=!1,r)=>{const i=["js","css","files"];let o=t,s=!1;if(r&&t.endsWith(".json"))try{o=X(e.readFileSync(t,"utf8"))}catch(e){return G(2,e,"[cli] No resources found.")}else o=X(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):F(3,"[cli] No resources found.")};function X(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const z=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=z(e[r]));return t},K=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function J(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(x).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(x[t]))})),console.log("\n")}const B=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Y=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&Y(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},Q=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Z={};const ee=()=>Z,te=(e,t,r=[])=>{const i=z(e);for(const[e,s]of Object.entries(t))i[e]="object"!=typeof(o=s)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==s?s:i[e]:te(i[e],s,r);var o;return i};function re(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],s=t&&t[i];void 0===o.value?re(o,s,`${r}.${i}`):(void 0!==s&&(o.value=s),o.envLink in $&&void 0!==$[o.envLink]&&(o.value=$[o.envLink]))}))}function ie(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:ie(i);return t}function oe(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=oe(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function se(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class ne extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ae={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},le=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ce=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),F(4,`[cache] Fetching script - ${e}.js`);const o=await se(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new ne(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return F(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},pe=async(t,i,o)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ae.cdnURL;F(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ae.sources=await(async(e,t,i,o,s)=>{let n;const a=o.host,l=o.port;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new ne("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:$.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ce(`${e}`,c,s,!0))),...t.map((e=>ce(`${e}`,c,s))),...i.map((e=>ce(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,i,l),ae.hcVersion=le(ae),e.writeFileSync(o,ae.sources),l}catch(e){throw new ne("[cache] Unable to update the local Highcharts cache.").setError(e)}},he=async r=>{const{highcharts:i,server:o}=r,s=t.join(D,i.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||i.forceFetch)F(3,"[cache] Fetching and caching Highcharts dependencies."),n=await pe(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:s,moduleScripts:c,indicatorScripts:p}=i,h=s.length+c.length+p.length;r.version!==i.version?(F(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==h?(F(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return F(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await pe(i,o.proxy,l):(F(3,"[cache] Dependency cache is up to date, proceeding."),ae.sources=e.readFileSync(l,"utf8"),n=r.modules,ae.hcVersion=le(ae))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ae.activeManifest=o,F(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(D,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ne("[cache] Error writing the cache manifest.").setError(e)}})(i,n)},ue=()=>t.join(D,ee().highcharts.cachePath);var de=async e=>{const t=ee();t?.highcharts&&(t.highcharts.version=e),await he(t)},ge=()=>ae,me=()=>ae.hcVersion;const fe=d.randomBytes(64).toString("base64url"),ve=h.join("tmp",`puppeteer-${fe}`),ye=[`--user-data-dir=${h.join(ve,"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"],we=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:b&&b.src||new URL("index.cjs",document.baseURI).href)),be=e.readFileSync(we+"/../templates/template.html","utf8");let Ee;const Te=async e=>{await e.setContent(be),await e.addScriptTag({path:`${ue()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Se=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){G(2,e,"[browser] Could not clear the content of the page.")}},xe=async()=>{if(!Ee)return!1;const e=await Ee.newPage();return await e.setCacheEnabled(!1),await Te(e),e};const Re=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:b&&b.src||new URL("index.cjs",document.baseURI).href)),Le=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ke=async(r,i,o)=>{const s=[],n=async e=>{for(const e of s)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{F(4,"[export] Determining export path.");const a=o.export;await r.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&ge().activeManifest.modules.debugger;let c;if(await r.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(F(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else F(4,"[export] Treating as config."),a.strInj?await Le(r,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await Le(r,i,o));const p=o.customLogic.resources;if(p){if(p.js&&s.push(await r.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const i=!t.startsWith("http");s.push(await r.addScriptTag(i?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){G(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let e=p.css.match(/@import\s*([^;]*);/g);if(e)for(let i of e)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?s.push(await r.addStyleTag({url:i})):o.customLogic.allowFileResources&&s.push(await r.addStyleTag({path:t.join(Re,i)})));s.push(await r.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const h=c?await r.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||a.height),d=Math.ceil(h?.chartWidth||a.width);await r.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await r.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let w;if(c||await r.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(a.scale)}),"svg"===a.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))w=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ne("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:u,x:v,y:y},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new ne(`[export] Unsupported output format ${a.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(r,u,d,"base64")}return await r.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await n(r),w}catch(e){return await n(r),e}};const _e={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe,Ie={},Ce=!1;const Ae={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await xe(),!e||e.isClosed())throw new ne("The page is invalid or closed.");F(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ne("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Ie.workLimit/2))}},validate:async e=>Ie.workLimit&&++e.workCount>Ie.workLimit?(F(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ie.workLimit}).`),!1):(await Se(e.page,!0),!0),destroy:e=>{F(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Ne=async e=>{if(Ie=e&&e.pool?{...e.pool}:{},Oe=e.puppeteerArgs,await(async e=>{const t=[...ye,...e||[]];if(!Ee){let e=0;const r=async()=>{try{F(3,`[browser] Attempting to get a browser instance (try ${++e}).`),Ee=await u.launch({headless:"new",args:t,userDataDir:"./tmp/",handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1})}catch(t){if(G(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;F(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r()}catch(e){throw new ne("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!Ee)throw new ne("[browser] Cannot find a browser to open.")}return Ee})(Oe),F(3,`[pool] Initializing pool with workers: min ${Ie.minWorkers}, max ${Ie.maxWorkers}.`),Ce)return F(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ie.minWorkers)>parseInt(Ie.maxWorkers)&&(Ie.minWorkers=Ie.maxWorkers);try{Ce=new c.Pool({...Ae,min:parseInt(Ie.minWorkers),max:parseInt(Ie.maxWorkers),acquireTimeoutMillis:Ie.acquireTimeout,createTimeoutMillis:Ie.createTimeout,destroyTimeoutMillis:Ie.destroyTimeout,idleTimeoutMillis:Ie.idleTimeout,createRetryIntervalMillis:Ie.createRetryInterval,reapIntervalMillis:Ie.reaperInterval,propagateCreateError:!1}),Ce.on("release",(async e=>{await Se(e.page,!1),F(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ce.on("destroySuccess",((e,t)=>{F(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ce.release(e)})),F(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ne("[pool] Could not create the pool of workers.").setError(e)}};async function Pe(){if(F(3,"[pool] Killing pool with all workers and closing browser."),Ce){for(const e of Ce.used)Ce.release(e.resource);Ce.destroyed||(await Ce.destroy(),F(4,"[browser] Destroyed the pool of resources."))}await(async()=>{Ee?.isConnected()&&await Ee.close(),F(4,"[browser] Closed the browser.")})()}const $e=async(e,t)=>{let r;try{if(F(4,"[pool] Work received, starting to process."),++_e.exportAttempts,Ie.benchmarking&&He(),!Ce)throw new ne("Work received, but pool has not been started.");try{F(4,"[pool] Acquiring a worker handle.");const e=Q();r=await Ce.acquire().promise,t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ne("Error encountered when acquiring an available entry.").setError(e)}if(F(4,"[pool] Acquired a worker handle."),!r.page)throw new ne("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();F(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=Q(),s=await ke(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await xe()),new ne("Error encountered during export.").setError(s);t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Ce.release(r);const n=(new Date).getTime()-i;return _e.timeSpent+=n,_e.spentAverage=_e.timeSpent/++_e.performedExports,F(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++_e.droppedExports,r&&Ce.release(r),new ne(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=Ce;F(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),F(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),F(5,`[pool] The number of resources that are currently available: ${Ce.numFree()}.`),F(5,`[pool] The number of resources that are currently acquired: ${Ce.numUsed()}.`),F(5,`[pool] The number of callers waiting to acquire a resource: ${Ce.numPendingAcquires()}.`)}var je=()=>({min:Ce.min,max:Ce.max,available:Ce.numFree(),inUse:Ce.numUsed(),pendingAcquire:Ce.numPendingAcquires()}),Ue=()=>_e;let Fe=!1;const Ge=async(t,r)=>{F(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=z(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=te(t,e,L),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,ee()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{F(4,"[chart] Attempting to export from a SVG input.");const e=Ve(function(e){const t=new g.JSDOM("").window;return m(t).sanitize(e)}(i.payload.svg),i,r);return++_e.exportFromSvgAttempts,e}catch(e){return r(new ne("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return F(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Ve(i.export.instr.trim(),i,r)}catch(e){return r(new ne("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return F(4,"[chart] Attempting to export from a raw input."),B(i.customLogic?.allowCodeExecution)?De(i,r):"string"==typeof o.instr?Ve(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new ne("[chart] Error loading raw input.").setError(e))}return r(new ne("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Me=e=>{const{chart:t,exporting:r}=e.export?.options||X(e.export?.instr),i=X(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},qe=async(t,r,i,o)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Fe;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=W(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=W(r,B(t.customLogic.allowFileResources))}catch(e){G(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return i(new ne("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=V(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=X(e.readFileSync(s[t],"utf8"),!0):s[t]=X(s[t],!0))}catch(e){s[t]={},G(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Y(n.customCode,n.allowFileResources)}catch(e){G(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,G(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...Me(t)};try{return i(!1,await $e(s.strInj||r||o,t))}catch(e){return i(e)}},De=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=K(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,qe(e,!1,t)}catch(r){return t(new ne(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ve=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return F(4,"[chart] Parsing input as SVG."),qe(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return qe(t,i,r)}catch(e){return B(i)?De(t,r):r(new ne("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},We=[],Xe=()=>{F(4,"[server] Clearing all registered intervals.");for(const e of We)clearInterval(e)},ze=(e,t,r,i)=>{G(1,e),"development"!==$.OTHER_NODE_ENV&&delete e.stack,i(e)},Ke=(e,t,r,i)=>{const{statusCode:o,status:s,message:n,stack:a}=e,l=o||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Je=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=w({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(F(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),F(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Be extends ne{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ye={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Qe=0;const Ze=[],et=[],tt=(e,t,r,i)=>{let o=!0;const{id:s,uniqueId:n,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,s,n,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},rt=async(e,t,r)=>{try{const r=Q(),o=p.v4().replace(/-/g,""),s=ee(),n=e.body,a=++Qe;let l=V(n.type);if(!n||"object"==typeof(i=n)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=X(n.infile||n.options||n.data);if(!c&&!n.svg)throw F(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let h=!1;if(h=tt(Ze,e,t,{id:a,uniqueId:o,type:l,body:n}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(()=>{u=!0})),F(4,`[export] Got an incoming HTTP request with ID ${o}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:X(n.globalOptions,!0),themeOptions:X(n.themeOptions,!0)},customLogic:{allowCodeExecution:Fe,allowFileResources:!1,resources:X(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=K(c,d.customLogic.allowCodeExecution));const g=te(s,d);if(g.export.options=c,g.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:o},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ge(g,((i,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&F(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),u)return F(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,tt(et,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ye[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const it=JSON.parse(e.readFileSync(t.join(D,"package.json"))),ot=new Date,st=[];function nt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Ue(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;st.push(t),st.length>30&&st.shift()}),6e4),We.push(t),e.get("/health",((e,t)=>{const r=Ue(),i=st.length,o=st.reduce(((e,t)=>e+t),0)/st.length;F(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:it.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:je(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const at=new Map,lt=v();lt.disable("x-powered-by"),lt.use(f());const ct=y.memoryStorage(),pt=y({storage:ct,limits:{fieldSize:52428800}});lt.use(v.json({limit:52428800})),lt.use(v.urlencoded({extended:!0,limit:52428800})),lt.use(pt.none());const ht=e=>{e.on("clientError",(e=>{G(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{G(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{G(1,e,`[server] Socket error: ${e.message}`)}))}))},ut=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(lt);ht(e),e.listen(r.port,r.host),at.set(r.port,e),F(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){F(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},lt);ht(e),e.listen(r.ssl.port,r.host),at.set(r.ssl.port,e),F(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Je(lt,r.rateLimiting),lt.use(v.static(t.posix.join(D,"public"))),nt(lt),(e=>{e.post("/",rt),e.post("/:filename",rt)})(lt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(D,"public","index.html"))}))})(lt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=$.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Be("No new version supplied.",400);try{await de(o)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(lt),(e=>{e.use(ze),e.use(Ke)})(lt)}catch(e){throw new ne("[server] Could not configure and start the server.").setError(e)}},dt=()=>{F(4,"[server] Closing all servers.");for(const[e,t]of at)t.close((()=>{F(4,`[server] Closed server on port: ${e}.`)}))};var gt={startServer:ut,closeServers:dt,getServers:()=>at,enableRateLimiting:e=>Je(lt,e),getExpress:()=>v,getApp:()=>lt,use:(e,...t)=>{lt.use(e,...t)},get:(e,...t)=>{lt.get(e,...t)},post:(e,...t)=>{lt.post(e,...t)}};const mt=async e=>{await Promise.allSettled([Xe(),dt(),Pe()]),process.exit(e)};var ft={server:gt,startServer:ut,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Fe=B(t),(e=>{M(e&&parseInt(e.level)),e&&e.dest&&q(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(F(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{F(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGTERM",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGHUP",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("uncaughtException",(async(e,t)=>{G(1,e,`The ${t} error.`),await mt(1)}))),await he(e),await Ne({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ge(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Pe()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Ge({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await Pe()}catch(e){throw new ne("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,setOptions:(t,r)=>(r?.length&&(Z=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){G(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),re(x,Z),Z=ie(x),t&&(Z=te(Z,t,L)),r?.length&&(Z=function(e,t,r){let i=!1;for(let o=0;o(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=B(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(F(2,`[config] Missing value for the '${s}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&J();return e}(Z,r,x)),Z),shutdownCleanUp:mt,log:F,logWithStack:G,setLogLevel:M,enableFileLogging:q,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=k[r]?k[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,s)=>{let n=0,a=[];for(const e of s)R[e]=R[e].map((t=>({...t,section:e}))),a=[...a,...R[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=oe(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){G(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(D,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(D+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:J};module.exports=ft; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9icm93c2VyLmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9jaGFydC5qcyIsIi4uL2xpYi9zYW5pdGl6ZS5qcyIsIi4uL2xpYi9pbnRlcnZhbHMuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvcmVzb3VyY2VfcmVsZWFzZS5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFBvc3NpYmxlIG5hbWVzIGZvciBIaWdoY2hhcnRzIHNjcmlwdHNcclxuZXhwb3J0IGNvbnN0IHNjcmlwdHNOYW1lcyA9IHtcclxuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICBtb2R1bGVzOiBbXHJcbiAgICAnc3RvY2snLFxyXG4gICAgJ21hcCcsXHJcbiAgICAnZ2FudHQnLFxyXG4gICAgJ2V4cG9ydGluZycsXHJcbiAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICdib29zdCcsXHJcbiAgICAnZGF0YScsXHJcbiAgICAnZGF0YS10b29scycsXHJcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAnaGVhdG1hcCcsXHJcbiAgICAndGlsZW1hcCcsXHJcbiAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgJ3RpbWVsaW5lJyxcclxuICAgICd0cmVlbWFwJyxcclxuICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICdkcmlsbGRvd24nLFxyXG4gICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgJ2J1bGxldCcsXHJcbiAgICAnZnVubmVsJyxcclxuICAgICdmdW5uZWwzZCcsXHJcbiAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAncHlyYW1pZDNkJyxcclxuICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgJ3BhcmV0bycsXHJcbiAgICAncGF0dGVybi1maWxsJyxcclxuICAgICdwaWN0b3JpYWwnLFxyXG4gICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAnc2Fua2V5JyxcclxuICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICdzdG9jay10b29scycsXHJcbiAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgJ3N1bmJ1cnN0JyxcclxuICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgJ3Zhcml3aWRlJyxcclxuICAgICd2ZWN0b3InLFxyXG4gICAgJ3Zlbm4nLFxyXG4gICAgJ3dpbmRiYXJiJyxcclxuICAgICd3b3JkY2xvdWQnLFxyXG4gICAgJ3hyYW5nZScsXHJcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICdkcmFnLXBhbmVzJyxcclxuICAgICdkZWJ1Z2dlcicsXHJcbiAgICAnZHVtYmJlbGwnLFxyXG4gICAgJ2xvbGxpcG9wJyxcclxuICAgICdjeWxpbmRlcicsXHJcbiAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICdkb3RwbG90JyxcclxuICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICdoZWlraW5hc2hpJyxcclxuICAgICdmbG93bWFwJ1xyXG4gIF0sXHJcbiAgaW5kaWNhdG9yczogWydpbmRpY2F0b3JzLWFsbCddXHJcbn07XHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcclxuLy8gaW5mb3JtYXRpb24gbGlrZTpcclxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XHJcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cclxuLy8gKiBTaG9ydCBkZXNjcmlwdGlvbiBvZiBhIGNob3NlbiBvcHRpb25cclxuLy8gKiBJbml0aWFsIHZhbHVlXHJcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdhcmdzJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH1cclxuICBdLFxyXG4gIGhpZ2hjaGFydHM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAndmVyc2lvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2RuVVJMJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgQ0ROJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvcmVTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBjb3JlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY29yZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnaW5kaWNhdG9yU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgaW5kaWNhdG9yIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuaW5kaWNhdG9yU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnY3VzdG9tU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jdXN0b21TY3JpcHRzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSByZS1mZXRjaCB0aGUgc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5mb3JjZUZldGNoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjYWNoZVBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jYWNoZVBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGV4cG9ydDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ3R5cGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZXhwb3J0IGZpbGUgdHlwZScsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29uc3RyJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGNvbnN0cnVjdG9yIGZvciBIaWdoY2hhcnRzJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdEhlaWdodC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFdpZHRoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0U2NhbGUudmFsdWUsXHJcbiAgICAgIG1pbjogMC4xLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmFzdGVyaXphdGlvblRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlbmRlcmluZyB3ZWJwYWdlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQucmFzdGVyaXphdGlvblRpbWVvdXQudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGN1c3RvbUxvZ2ljOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBleGVjdXRpb24gb2YgY3VzdG9tIGNvZGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0ZpbGVSZXNvdXJjZXMnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGZpbGUgcmVzb3VyY2VzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHNlcnZlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgdGhlIHNlcnZlciBvbiAwLjAuMC4wJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdob3N0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBob3N0bmFtZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBzZXJ2ZXIgYmVuY2htYXJraW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdwcm94eS5ob3N0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwcm94eS5wb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwcm94eS50aW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHNlcnZpbmcgb25seSBvdmVyIEhUVFBTJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmZvcmNlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3NzbC5wb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NTTCBzZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5jZXJ0UGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgcG9vbDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21pbldvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGluaXRpYWwgbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWluV29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtYXhXb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnd29ya0xpbWl0JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIFB1cHBldGVlciBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLndvcmtMaW1pdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5hY3F1aXJlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZXN0cm95VGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuZGVzdHJveVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnaWRsZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYWZ0ZXIgYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuaWRsZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlUmV0cnlJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZXRyeSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgYSBjcmVhdGUgcHJvY2VzcyBmYWlscycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVSZXRyeUludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JlYXBlckludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJlYXBlciBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgdHJpZ2dlcmluZyB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3knLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVySW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBiZW5jaG1hcmtpbmcgZm9yIGEgcmVzb3VyY2UgcG9vbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGxvZ2dpbmc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdsZXZlbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSwgNTogYmVuY2htYXJrKScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5sZXZlbC52YWx1ZSxcclxuICAgICAgcm91bmQ6IDAsXHJcbiAgICAgIG1pbjogMCxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdmaWxlJyxcclxuICAgICAgbWVzc2FnZTogJ0EgbG9nIGZpbGUgbmFtZS4gU2V0IHdpdGggdGhlIC0tbG9nRGVzdCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2Rlc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gbG9nIGZpbGVzLiBFbmFibGVzIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5kZXN0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICB1aTogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JvdXRlJyxcclxuICAgICAgbWVzc2FnZTogJ0Egcm91dGUgdG8gYXR0YWNoIHRoZSBVSScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIG90aGVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ25vZGVFbnYnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9kZUVudi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdub0xvZ28nLFxyXG4gICAgICBtZXNzYWdlOiAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwLiBSZXBsYWNlZCBieSBzaW1wbGUgdGV4dCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9Mb2dvLnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259YFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJlcy50ZXh0ID0gZGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIHNvdXJjZVBhdGhcclxuKSA9PiB7XHJcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XHJcbiAgY29uc3QgaGNWZXJzaW9uID0gdmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIXZlcnNpb24gPyAnJyA6IGAke3ZlcnNpb259L2A7XHJcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259JHtjfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2NkblVSTH0ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcclxuICAgICAgICAgIChpKSA9PiBgJHtjZG5VUkx9c3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgcHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PiB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xyXG4gICAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG4gIH1cclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBoaWdoY2hhcnRzLCBzZXJ2ZXIgfSA9IG9wdGlvbnM7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xyXG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0cztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgICAgICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICAgICAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgICAgICAgIGhhbmRsZVNJR0hVUDogZmFsc2VcclxuICAgICAgICB9KTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IGFzeW5jICgpID0+IHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBicm93c2VyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uaXNDb25uZWN0ZWQoKSkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgZ2V0LFxyXG4gIGNsb3NlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT5cclxuICBwYWdlLnBkZih7XHJcbiAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcclxuICAgIHdpZHRoLFxyXG4gICAgZW5jb2RpbmdcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XHJcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cclxuICovXHJcbmNvbnN0IHNldEFzQ29uZmlnID0gKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PlxyXG4gIHBhZ2UuZXZhbHVhdGUoXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIChjaGFydCwgb3B0aW9ucykgPT4gd2luZG93LnRyaWdnZXJFeHBvcnQoY2hhcnQsIG9wdGlvbnMpLFxyXG4gICAgY2hhcnQsXHJcbiAgICBvcHRpb25zXHJcbiAgKTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAqIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICovXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xyXG4gIGNvbnN0IGNsZWFySW5qZWN0ZWQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gICAgZm9yIChjb25zdCByZXMgb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcclxuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcclxuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4ubGlua3NUb1JlbW92ZVxyXG4gICAgICBdKSB7XHJcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIEZvcmNlIGEgckFGXHJcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3B1cHBldGVlci9wdXBwZXRlZXIvaXNzdWVzLzc1MDdcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge30pKTtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoZCkgPT4gKHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGQpLCBkaXNwbGF5RXJyb3JzKTtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgICBjb25zdCByZXNvdXJjZXMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcztcclxuICAgIGlmIChyZXNvdXJjZXMpIHtcclxuICAgICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgICBpZiAocmVzb3VyY2VzLmpzKSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKFxyXG4gICAgICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgICAgICA/IHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2V4cG9ydF0gVGhlIEpTIGZpbGUgJHtmaWxlfSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplXHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLFxyXG4gICAgICAgICAgKGVsZW1lbnQsIHNjYWxlKSA9PiAoe1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodDogZWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlLFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoOiBlbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZVxyXG4gICAgICAgICAgfSksXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICAgICAgKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHZpZXdwb3J0IGZvciB0aGUgZmlyc3QgdGltZVxyXG4gICAgLy8gTk9URTogdGhlIGNhbGwgdG8gc2V0Vmlld3BvcnQgaXMgZXhwZW5zaXZlIC0gY2FuIHdlIGdldCBhd2F5IHdpdGggb25seVxyXG4gICAgLy8gY2FsbGluZyBpdCBvbmNlLCBlLmcuIG1vdmluZyB0aGlzIG9uZSBpbnRvIHRoZSBpc1NWRyBjb25kaXRpb24gYmVsb3c/XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIGEgem9vbSBjYWxsYmFjayBmb3IgdGhlIG5leHQgZXZhbHVhdGUgY2FsbFxyXG4gICAgY29uc3Qgem9vbUNhbGxiYWNrID0gaXNTVkdcclxuICAgICAgPyAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgIChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG4gICAgICAgIH1cclxuICAgICAgOiAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcclxuICAgICAgICB9O1xyXG5cclxuICAgIC8vIFNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSh6b29tQ2FsbGJhY2ssIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IGhlaWdodCwgd2lkdGgsIHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgaWYgKCFpc1NWRykge1xyXG4gICAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcclxuICAgICAgICBoZWlnaHQ6IE1hdGgucm91bmQoaGVpZ2h0KSxcclxuICAgICAgICBkZXZpY2VTY2FsZUZhY3RvcjogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgZGF0YTtcclxuICAgIC8vIFJBU1RFUklaQVRJT05cclxuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgIC8vIFNWR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUG9vbCBzdGF0aXN0aWNzXHJcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcclxuICBwZXJmb3JtZWRFeHBvcnRzOiAwLFxyXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXHJcbiAgc3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIEN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbmxldCBwdXBwZXRlZXJBcmdzO1xyXG5cclxuY29uc3QgZmFjdG9yeSA9IHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlciBwYWdlIGZvciB0aGUgZXhwb3J0IHBvb2wuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxyXG4gICAqIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWwgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XHJcbiAgICogcGFnZS5cclxuICAgKi9cclxuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgIGxldCBwYWdlID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XHJcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBwYWdlID0gYXdhaXQgYnJvd3Nlck5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHBhZ2VcclxuICAgIGF3YWl0IGNsZWFyUGFnZSh3b3JrZXJIYW5kbGUucGFnZSwgdHJ1ZSk7XHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXHJcbiAgICovXHJcbiAgZGVzdHJveTogKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgbG9nKDMsIGBbcG9vbF0gRGVzdHJveWluZyBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gV2UgZG9uJ3QgcmVhbGx5IG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIFRoZSBuZXdlc3QgcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIGJyb3dzZXIgY3JlYXRpb25cclxuICBwdXBwZXRlZXJBcmdzID0gY29uZmlnLnB1cHBldGVlckFyZ3M7XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxyXG4gICk7XHJcblxyXG4gIGlmIChwb29sKSB7XHJcbiAgICByZXR1cm4gbG9nKFxyXG4gICAgICA0LFxyXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xyXG4gICAgcG9vbENvbmZpZy5taW5Xb3JrZXJzID0gcG9vbENvbmZpZy5tYXhXb3JrZXJzO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXHJcbiAgICAgIC4uLmZhY3RvcnksXHJcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcclxuICAgICAgbWF4OiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogS2lsbHMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGJyb3dzZXJDbG9zZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5LidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydC4nKS5zZXRFcnJvcihcclxuICAgICAgICByZXN1bHRcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxyXG4gIGluVXNlOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nQWNxdWlyZTogcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHsgbWluLCBtYXggfSA9IHBvb2w7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB0aGF0IGFyZSBjdXJyZW50bHkgYXZhaWxhYmxlOiAke3Bvb2wubnVtRnJlZSgpfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB0aGF0IGFyZSBjdXJyZW50bHkgYWNxdWlyZWQ6ICR7cG9vbC5udW1Vc2VkKCl9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgY2FsbGVycyB3YWl0aW5nIHRvIGFjcXVpcmUgYSByZXNvdXJjZTogJHtwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpfS5gXHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbEluZm8sXHJcbiAgZ2V0UG9vbEluZm9KU09OLFxyXG4gIGdldFN0YXRzOiAoKSA9PiBzdGF0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGV4cG9ydEFzU3RyaW5nKFxyXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICApO1xyXG5cclxuICAgICAgKytzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHM7XHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcclxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgc2luZ2xlIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXHJcbiAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBvdXRmaWxlLCB0eXBlIH0gPSBpbmZvLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcclxuICAgICk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICoqL1xyXG5cclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxyXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxyXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgc2FuaXRpemU7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbmNvbnN0IGludGVydmFsSWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiBhIHNldEludGVydmFsIHRvIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBhZGRJbnRlcnZhbCA9IChpZCkgPT4ge1xyXG4gIGludGVydmFsSWRzLnB1c2goaWQpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYnkgaWRzIGdhdGhlcmVkIGluIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhckFsbEludGVydmFscyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIGludGVydmFsSWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkSW50ZXJ2YWwsXHJcbiAgY2xlYXJBbGxJbnRlcnZhbHNcclxufTtcclxuIiwiaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBhZGRJbnRlcnZhbCB9IGZyb20gJy4uLy4uL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XHJcblxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwOyAvLyByZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDsgLy8gMzAgbWludXRlc1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIHN1Y2Nlc3NSYXRlc1xyXG4gKiBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgY29uc3Qgc3VtID0gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xyXG4gIHJldHVybiBzdW0gLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGdhdGhlcnNcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U3VjY2Vzc1JhdGUgPSAoKSA9PlxyXG4gIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xyXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgaWYgKCFhcHApIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxyXG4gIGFkZEludGVydmFsKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgIGxvZyg0LCAnW2hlYWx0aC5qc10gR0VUIC9oZWFsdGggWzIwMF0gLSByZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICByZXMuc2VuZCh7XHJcbiAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgdXB0aW1lOlxyXG4gICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxyXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxyXG4gICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzLFxyXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcclxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxyXG4gICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDAsXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgIHBlcmlvZCxcclxuICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgbWVzc2FnZTogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgIC8vIFNWRy9KU09OIGF0dGVtcHRzXHJcbiAgICAgIHN2Z0V4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgIGpzb25FeHBvcnRBdHRlbXB0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAtIHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0c1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tICcuL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXHJcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbmFwcC51c2UoY29ycygpKTtcclxuXHJcbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcclxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgc3RvcmFnZSxcclxuICBsaW1pdHM6IHtcclxuICAgIGZpZWxkU2l6ZTogNTAgKiAxMDI0ICogMTAyNFxyXG4gIH1cclxufSk7XHJcblxyXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcbmFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuXHJcbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG5hcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi4gVGhlIGBzZXJ2ZXJDb25maWdgXHJcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXHJcbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNlcnZlciBjYW5ub3QgYmUgY29uZmlndXJlZFxyXG4gKiBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFNlcnZlciA9IGFzeW5jIChzZXJ2ZXJDb25maWcpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xyXG4gICAgaWYgKFxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXHJcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxyXG4gICAgKSB7XHJcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGUoYXBwKTtcclxuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XHJcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICpcclxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLnBvc3QoXHJcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXHJcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXI/LmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIE90aGVyXHJcbiAgc2V0T3B0aW9ucyxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsic2NyaXB0c05hbWVzIiwiY29yZSIsIm1vZHVsZXMiLCJpbmRpY2F0b3JzIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibG9nZ2luZyIsImxldmVsIiwiZmlsZSIsImRlc3QiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub2RlRW52IiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJub0xvZ28iLCJwcm9tcHRzQ29uZmlnIiwibmFtZSIsIm1lc3NhZ2UiLCJpbml0aWFsIiwiam9pbiIsInNlcGFyYXRvciIsImluc3RydWN0aW9ucyIsImNob2ljZXMiLCJoaW50IiwibWluIiwibWF4Iiwicm91bmQiLCJhYnNvbHV0ZVByb3BzIiwibmVzdGVkQXJncyIsImNyZWF0ZU5lc3RlZEFyZ3MiLCJvYmoiLCJwcm9wQ2hhaW4iLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImsiLCJpbmNsdWRlcyIsImVudHJ5Iiwic3Vic3RyaW5nIiwidW5kZWZpbmVkIiwiZG90ZW52IiwiY29uZmlnIiwidiIsImZpbHRlckFycmF5IiwieiIsInN0cmluZyIsInRyYW5zZm9ybSIsInNwbGl0IiwibWFwIiwidHJpbSIsImZpbHRlciIsImxlbmd0aCIsImVudW0iLCJ2YWx1ZXMiLCJyZWZpbmUiLCJpc05hTiIsInBhcnNlRmxvYXQiLCJlbnZzIiwib2JqZWN0IiwiSElHSENIQVJUU19WRVJTSU9OIiwidGVzdCIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsInN0YXJ0c1dpdGgiLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfREVGQVVMVF9IRUlHSFQiLCJFWFBPUlRfREVGQVVMVF9XSURUSCIsIkVYUE9SVF9ERUZBVUxUX1NDQUxFIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX0JFTkNITUFSS0lORyIsIlNFUlZFUl9QUk9YWV9IT1NUIiwiU0VSVkVSX1BST1hZX1BPUlQiLCJTRVJWRVJfUFJPWFlfVElNRU9VVCIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4iLCJTRVJWRVJfU1NMX0VOQUJMRSIsIlNFUlZFUl9TU0xfRk9SQ0UiLCJTRVJWRVJfU1NMX1BPUlQiLCJTRVJWRVJfU1NMX0NFUlRfUEFUSCIsIlBPT0xfTUlOX1dPUktFUlMiLCJQT09MX01BWF9XT1JLRVJTIiwiUE9PTF9XT1JLX0xJTUlUIiwiUE9PTF9BQ1FVSVJFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9USU1FT1VUIiwiUE9PTF9ERVNUUk9ZX1RJTUVPVVQiLCJQT09MX0lETEVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMIiwiUE9PTF9SRUFQRVJfSU5URVJWQUwiLCJQT09MX0JFTkNITUFSS0lORyIsIkxPR0dJTkdfTEVWRUwiLCJMT0dHSU5HX0ZJTEUiLCJMT0dHSU5HX0RFU1QiLCJVSV9FTkFCTEUiLCJVSV9ST1VURSIsIk9USEVSX05PREVfRU5WIiwiT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMiLCJPVEhFUl9OT19MT0dPIiwicGFydGlhbCIsInBhcnNlIiwicHJvY2VzcyIsImVudiIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImVycm9yIiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwiRGF0ZSIsInRvU3RyaW5nIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIml0ZW0iLCJkYXRhIiwicGFyc2VkRGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwidGV4dCIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwicmVzcG9uc2UiLCJ1cGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwicHJveHlPcHRpb25zIiwic291cmNlUGF0aCIsInByb3h5QWdlbnQiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJmZXRjaFNjcmlwdHMiLCJjIiwibSIsIndyaXRlRmlsZVN5bmMiLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwibWFuaWZlc3RQYXRoIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlTWFwIiwibnVtYmVyT2ZNb2R1bGVzIiwic29tZSIsIm1vZHVsZU5hbWUiLCJuZXdNYW5pZmVzdCIsInNhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0Q2FjaGVQYXRoIiwiY2FjaGUkMSIsIm5ld1ZlcnNpb24iLCJSQU5ET01fUElEIiwicmFuZG9tQnl0ZXMiLCJQVVBQRVRFRVJfRElSIiwicGF0aCIsIm1pbmltYWxBcmdzIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJzZXRQYWdlQ29udGVudCIsInBhZ2UiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwiZXZhbHVhdGUiLCJzZXR1cEhpZ2hjaGFydHMiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJfZGlzcGxheUVycm9ycyIsImlubmVySFRNTCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJib2R5IiwibmV3UGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwiY2hhcnQiLCJ0cmlnZ2VyRXhwb3J0IiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwiZGlzcG9zZSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsImRpc3BsYXlFcnJvcnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwiZCIsInN2Z1RlbXBsYXRlIiwic3RySW5qIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiYWRkU3R5bGVUYWciLCJzaXplIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsIkhpZ2hjaGFydHMiLCJjaGFydHMiLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJ6b29tQ2FsbGJhY2siLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ4IiwieSIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsIm91dGVySFRNTCIsImNyZWF0ZVNWRyIsImVuY29kaW5nIiwiY2xpcCIsInJhY2UiLCJzY3JlZW5zaG90Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsInBkZiIsImNyZWF0ZVBERiIsIm9sZENoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwdXBwZXRlZXJBcmdzIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiY2xvc2UiLCJpbml0UG9vbCIsImFsbEFyZ3MiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJoZWFkbGVzcyIsInVzZXJEYXRhRGlyIiwiaGFuZGxlU0lHSU5UIiwiaGFuZGxlU0lHVEVSTSIsImhhbmRsZVNJR0hVUCIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwicmVzb3VyY2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImlzQ29ubmVjdGVkIiwiYnJvd3NlckNsb3NlIiwicG9zdFdvcmsiLCJnZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwicGF5bG9hZCIsInJlcXVlc3RJZCIsIndvcmtTdGFydCIsImV4cG9ydENvdW50ZXIiLCJyZXN1bHQiLCJleHBvcnRUaW1lIiwibnVtRnJlZSIsIm51bVVzZWQiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJhdmFpbGFibGUiLCJpblVzZSIsInBlbmRpbmdBY3F1aXJlIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJpbnB1dCIsIkpTRE9NIiwiRE9NUHVyaWZ5Iiwic2FuaXRpemUiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwiZXhwb3J0aW5nIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsImVuYWJsZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImRlZmF1bHRPcHRpb25zIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsInBhcmFtcyIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJzZXRPcHRpb25zIiwidXNlck9wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwcm9wIiwicGFpckFyZ3VtZW50VmFsdWUiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlzZXMiLCJ3cml0ZUZpbGUiLCJwcmludExvZ28iLCJwYWNrYWdlVmVyc2lvbiJdLCJtYXBwaW5ncyI6IjZ3QkFlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSxjQUNBLHVCQUNBLGdCQUNBLHVCQUNBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNBLFVBQ0EsVUFDQSxjQUNBLFdBQ0EsVUFDQSxZQUNBLGNBQ0EsWUFDQSxzQkFDQSxTQUNBLFNBQ0EsV0FDQSxhQUNBLFlBQ0EsZUFDQSx5QkFDQSxTQUNBLGVBQ0EsWUFDQSxrQkFDQSxTQUNBLGNBQ0EsbUJBQ0EsZUFDQSxjQUNBLGVBQ0EsY0FDQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsV0FFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sR0FDUEMsS0FBTSxXQUNOQyxZQUFhLDBDQUdqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BKLE1BQU8sU0FDUEMsS0FBTSxTQUNOSSxRQUFTLHFCQUNUSCxZQUFhLHNDQUVmSSxPQUFRLENBQ05OLE1BQU8sK0JBQ1BDLEtBQU0sU0FDTkksUUFBUyxxQkFDVEgsWUFBYSxrREFFZkssWUFBYSxDQUNYUCxNQUFPUCxFQUFhQyxLQUNwQk8sS0FBTSxXQUNOSSxRQUFTLDBCQUNUSCxZQUFhLHlDQUVm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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("node:path"),h=require("puppeteer"),d=require("node:crypto"),g=require("jsdom"),m=require("dompurify"),f=require("cors"),v=require("express"),y=require("multer"),b=require("express-rate-limit"),w="undefined"!=typeof document?document.currentScript:null;function E(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var T=E(n);const S={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},x={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:S.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:S.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:S.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!1,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:250,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},R={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:x.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:x.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:x.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:x.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:x.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:x.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${x.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${x.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:x.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:x.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:x.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:x.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:x.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:x.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:x.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:x.server.host.value},{type:"number",name:"port",message:"Server port",initial:x.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:x.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:x.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:x.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:x.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:x.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:x.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:x.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:x.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:x.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:x.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:x.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:x.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:x.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:x.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:x.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:x.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:x.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:x.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:x.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:x.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:x.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:x.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:x.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:x.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:x.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:x.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:x.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:x.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:x.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:x.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:x.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:x.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:x.other.noLogo.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:x.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:x.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:x.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:x.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:x.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:x.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:x.debug.debuggingPort.value}]},L=["options","globalOptions","themeOptions","resources","payload"],_={},k=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?k(i,`${t}.${r}`):(_[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(_[i.legacyName]=`${t}.${r}`.substring(1)))}}))};k(x),o.config();const O=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),I=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),C=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),A=()=>s.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),N=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),P=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=s.z.object({HIGHCHARTS_VERSION:s.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:s.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(S.core),HIGHCHARTS_MODULE_SCRIPTS:O(S.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(S.indicators),HIGHCHARTS_FORCE_FETCH:I(),HIGHCHARTS_CACHE_PATH:A(),HIGHCHARTS_ADMIN_TOKEN:A(),EXPORT_TYPE:C(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:C(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:N(),EXPORT_DEFAULT_WIDTH:N(),EXPORT_DEFAULT_SCALE:N(),EXPORT_RASTERIZATION_TIMEOUT:P(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:I(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:I(),SERVER_ENABLE:I(),SERVER_HOST:A(),SERVER_PORT:N(),SERVER_BENCHMARKING:I(),SERVER_PROXY_HOST:A(),SERVER_PROXY_PORT:N(),SERVER_PROXY_TIMEOUT:P(),SERVER_RATE_LIMITING_ENABLE:I(),SERVER_RATE_LIMITING_MAX_REQUESTS:P(),SERVER_RATE_LIMITING_WINDOW:P(),SERVER_RATE_LIMITING_DELAY:P(),SERVER_RATE_LIMITING_TRUST_PROXY:I(),SERVER_RATE_LIMITING_SKIP_KEY:A(),SERVER_RATE_LIMITING_SKIP_TOKEN:A(),SERVER_SSL_ENABLE:I(),SERVER_SSL_FORCE:I(),SERVER_SSL_PORT:N(),SERVER_SSL_CERT_PATH:A(),POOL_MIN_WORKERS:P(),POOL_MAX_WORKERS:P(),POOL_WORK_LIMIT:N(),POOL_ACQUIRE_TIMEOUT:P(),POOL_CREATE_TIMEOUT:P(),POOL_DESTROY_TIMEOUT:P(),POOL_IDLE_TIMEOUT:P(),POOL_CREATE_RETRY_INTERVAL:P(),POOL_REAPER_INTERVAL:P(),POOL_BENCHMARKING:I(),LOGGING_LEVEL:s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:A(),LOGGING_DEST:A(),UI_ENABLE:I(),UI_ROUTE:A(),OTHER_NODE_ENV:C(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:I(),OTHER_NO_LOGO:I(),DEBUG_ENABLE:I(),DEBUG_HEADLESS:I(),DEBUG_DEVTOOLS:I(),DEBUG_LISTEN_TO_CONSOLE:I(),DEBUG_DUMPIO:I(),DEBUG_SLOW_MO:P(),DEBUG_DEBUGGING_PORT:N()}).partial().parse(process.env),H=["red","yellow","blue","gray","green"];let U={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:H[0]},{title:"warning",color:H[1]},{title:"notice",color:H[2]},{title:"verbose",color:H[3]},{title:"benchmark",color:H[4]}],listeners:[]};for(const[e,t]of Object.entries(x.logging))U[e]=t.value;const j=(t,r)=>{U.toFile&&(U.pathCreated||(!e.existsSync(U.dest)&&e.mkdirSync(U.dest),U.pathCreated=!0),e.appendFile(`${U.dest}${U.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),U.toFile=!1)})))},G=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=U;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;U.listeners.forEach((e=>{e(s,r.join(" "))})),U.toConsole&&console.log.apply(void 0,[s.toString()[U.levelsDesc[t-1].color]].concat(r)),j(r,s)},F=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:s}=U;if(0===e||e>o||o>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];U.toConsole&&console.log.apply(void 0,[n.toString()[U.levelsDesc[e-1].color]].concat([i[H[e-1]],"\n",a])),U.listeners.forEach((e=>{e(n,l.join(" "))})),j(l,n)},D=e=>{e>=0&&e<=U.levelsDesc.length&&(U.level=e)},M=(e,t)=>{if(U={...U,dest:e||U.dest,file:t||U.file,toFile:!0},0===U.dest.length)return G(1,"[logger] File logging initialization: no path supplied.");U.dest.endsWith("/")||(U.dest+="/")},q=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),V=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},W=(t=!1,r)=>{const i=["js","css","files"];let o=t,s=!1;if(r&&t.endsWith(".json"))try{o=B(e.readFileSync(t,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else o=B(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):G(3,"[cli] No resources found.")};function B(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const X=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=X(e[r]));return t},z=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function K(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(x).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(x[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Y=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&Y(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},Q=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Z={};const ee=()=>Z,te=(e,t,r=[])=>{const i=X(e);for(const[e,s]of Object.entries(t))i[e]="object"!=typeof(o=s)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==s?s:i[e]:te(i[e],s,r);var o;return i};function re(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],s=t&&t[i];void 0===o.value?re(o,s,`${r}.${i}`):(void 0!==s&&(o.value=s),o.envLink in $&&void 0!==$[o.envLink]&&(o.value=$[o.envLink]))}))}function ie(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:ie(i);return t}function oe(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=oe(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function se(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class ne extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ae={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},le=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ce=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),G(4,`[cache] Fetching script - ${e}.js`);const o=await se(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new ne(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return G(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},pe=async(t,i,o)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ae.cdnURL;G(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ae.sources=await(async(e,t,i,o,s)=>{let n;const a=o.host,l=o.port;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new ne("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:$.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ce(`${e}`,c,s,!0))),...t.map((e=>ce(`${e}`,c,s))),...i.map((e=>ce(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,i,l),ae.hcVersion=le(ae),e.writeFileSync(o,ae.sources),l}catch(e){throw new ne("[cache] Unable to update the local Highcharts cache.").setError(e)}},ue=async r=>{const{highcharts:i,server:o}=r,s=t.join(q,i.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||i.forceFetch)G(3,"[cache] Fetching and caching Highcharts dependencies."),n=await pe(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:s,moduleScripts:c,indicatorScripts:p}=i,u=s.length+c.length+p.length;r.version!==i.version?(G(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(G(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return G(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await pe(i,o.proxy,l):(G(3,"[cache] Dependency cache is up to date, proceeding."),ae.sources=e.readFileSync(l,"utf8"),n=r.modules,ae.hcVersion=le(ae))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ae.activeManifest=o,G(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(q,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ne("[cache] Error writing the cache manifest.").setError(e)}})(i,n)},he=()=>t.join(q,ee().highcharts.cachePath);var de=async e=>{const t=ee();t?.highcharts&&(t.highcharts.version=e),await ue(t)},ge=()=>ae,me=()=>ae.hcVersion;const fe=d.randomBytes(64).toString("base64url"),ve=u.join("tmp",`puppeteer-${fe}`),ye=[`--user-data-dir=${u.join(ve,"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"],be=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),we=e.readFileSync(be+"/../templates/template.html","utf8");let Ee;const Te=async e=>{await e.setContent(we),await e.addScriptTag({path:`${he()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Se=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){F(2,e,"[browser] Could not clear the content of the page.")}},xe=async()=>{if(!Ee)return!1;const e=await Ee.newPage();return await e.setCacheEnabled(!1),await Te(e),e};const Re=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),Le=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var _e=async(r,i,o)=>{const s=[],n=async e=>{for(const e of s)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{G(4,"[export] Determining export path.");const a=o.export;await r.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&ge().activeManifest.modules.debugger;let c;if(await r.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(G(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else G(4,"[export] Treating as config."),a.strInj?await Le(r,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await Le(r,i,o));const p=o.customLogic.resources;if(p){if(p.js&&s.push(await r.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const i=!t.startsWith("http");s.push(await r.addScriptTag(i?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){F(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let e=p.css.match(/@import\s*([^;]*);/g);if(e)for(let i of e)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?s.push(await r.addStyleTag({url:i})):o.customLogic.allowFileResources&&s.push(await r.addStyleTag({path:t.join(Re,i)})));s.push(await r.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=c?await r.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),h=Math.ceil(u?.chartHeight||a.height),d=Math.ceil(u?.chartWidth||a.width);await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await r.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let b;if(c||await r.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(a.scale)}),"svg"===a.type)b=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))b=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ne("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:v,y:y},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new ne(`[export] Unsupported output format ${a.type}.`);b=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(r,h,d,"base64")}return await r.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await n(r),b}catch(e){return await n(r),e}};const ke={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe,Ie={},Ce=!1;const Ae={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await xe(),!e||e.isClosed())throw new ne("The page is invalid or closed.");G(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ne("Error encountered when creating a new page.").setError(e)}const{debug:i}=ee();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ie.workLimit/2))}},validate:async e=>Ie.workLimit&&++e.workCount>Ie.workLimit?(G(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ie.workLimit}).`),!1):(await Se(e.page,!0),!0),destroy:e=>{G(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Ne=async e=>{if(Ie=e&&e.pool?{...e.pool}:{},Oe=e.puppeteerArgs,await(async e=>{const t=[...ye,...e||[]],{enable:r,...i}=ee().debug,o={headless:"new",userDataDir:"./tmp/",args:t,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,...r&&i};if(!Ee){let e=0;const t=async()=>{try{G(3,`[browser] Attempting to get a browser instance (try ${++e}).`),Ee=await h.launch(o)}catch(r){if(F(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;G(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t()}catch(e){throw new ne("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!Ee)throw new ne("[browser] Cannot find a browser to open.")}return Ee})(Oe),G(3,`[pool] Initializing pool with workers: min ${Ie.minWorkers}, max ${Ie.maxWorkers}.`),Ce)return G(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ie.minWorkers)>parseInt(Ie.maxWorkers)&&(Ie.minWorkers=Ie.maxWorkers);try{Ce=new c.Pool({...Ae,min:parseInt(Ie.minWorkers),max:parseInt(Ie.maxWorkers),acquireTimeoutMillis:Ie.acquireTimeout,createTimeoutMillis:Ie.createTimeout,destroyTimeoutMillis:Ie.destroyTimeout,idleTimeoutMillis:Ie.idleTimeout,createRetryIntervalMillis:Ie.createRetryInterval,reapIntervalMillis:Ie.reaperInterval,propagateCreateError:!1}),Ce.on("release",(async e=>{await Se(e.page,!1),G(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ce.on("destroySuccess",((e,t)=>{G(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ce.release(e)})),G(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ne("[pool] Could not create the pool of workers.").setError(e)}};async function Pe(){if(G(3,"[pool] Killing pool with all workers and closing browser."),Ce){for(const e of Ce.used)Ce.release(e.resource);Ce.destroyed||(await Ce.destroy(),G(4,"[browser] Destroyed the pool of resources."))}await(async()=>{Ee?.isConnected()&&await Ee.close(),G(4,"[browser] Closed the browser.")})()}const $e=async(e,t)=>{let r;try{if(G(4,"[pool] Work received, starting to process."),++ke.exportAttempts,Ie.benchmarking&&He(),!Ce)throw new ne("Work received, but pool has not been started.");try{G(4,"[pool] Acquiring a worker handle.");const e=Q();r=await Ce.acquire().promise,t.server.benchmarking&&G(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ne("Error encountered when acquiring an available entry.").setError(e)}if(G(4,"[pool] Acquired a worker handle."),!r.page)throw new ne("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();G(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=Q(),s=await _e(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await xe()),new ne("Error encountered during export.").setError(s);t.server.benchmarking&&G(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Ce.release(r);const n=(new Date).getTime()-i;return ke.timeSpent+=n,ke.spentAverage=ke.timeSpent/++ke.performedExports,G(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++ke.droppedExports,r&&Ce.release(r),new ne(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=Ce;G(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),G(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),G(5,`[pool] The number of resources that are currently available: ${Ce.numFree()}.`),G(5,`[pool] The number of resources that are currently acquired: ${Ce.numUsed()}.`),G(5,`[pool] The number of callers waiting to acquire a resource: ${Ce.numPendingAcquires()}.`)}var Ue=()=>({min:Ce.min,max:Ce.max,available:Ce.numFree(),inUse:Ce.numUsed(),pendingAcquire:Ce.numPendingAcquires()}),je=()=>ke;let Ge=!1;const Fe=async(t,r)=>{G(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=X(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=te(t,e,L),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,ee()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{G(4,"[chart] Attempting to export from a SVG input.");const e=Ve(function(e){const t=new g.JSDOM("").window;return m(t).sanitize(e)}(i.payload.svg),i,r);return++ke.exportFromSvgAttempts,e}catch(e){return r(new ne("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return G(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Ve(i.export.instr.trim(),i,r)}catch(e){return r(new ne("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return G(4,"[chart] Attempting to export from a raw input."),J(i.customLogic?.allowCodeExecution)?qe(i,r):"string"==typeof o.instr?Ve(o.instr.trim(),i,r):Me(i,o.instr||o.options,r)}catch(e){return r(new ne("[chart] Error loading raw input.").setError(e))}return r(new ne("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},De=e=>{const{chart:t,exporting:r}=e.export?.options||B(e.export?.instr),i=B(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Me=async(t,r,i,o)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ge;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=W(t.customLogic.resources,J(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=W(r,J(t.customLogic.allowFileResources))}catch(e){F(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return i(new ne("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=V(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=B(e.readFileSync(s[t],"utf8"),!0):s[t]=B(s[t],!0))}catch(e){s[t]={},F(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Y(n.customCode,n.allowFileResources)}catch(e){F(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,F(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...De(t)};try{return i(!1,await $e(s.strInj||r||o,t))}catch(e){return i(e)}},qe=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=z(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Me(e,!1,t)}catch(r){return t(new ne(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ve=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return G(4,"[chart] Parsing input as SVG."),Me(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Me(t,i,r)}catch(e){return J(i)?qe(t,r):r(new ne("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},We=[],Be=()=>{G(4,"[server] Clearing all registered intervals.");for(const e of We)clearInterval(e)},Xe=(e,t,r,i)=>{F(1,e),"development"!==$.OTHER_NODE_ENV&&delete e.stack,i(e)},ze=(e,t,r,i)=>{const{statusCode:o,status:s,message:n,stack:a}=e,l=o||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ke=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=b({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(G(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),G(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends ne{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ye={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Qe=0;const Ze=[],et=[],tt=(e,t,r,i)=>{let o=!0;const{id:s,uniqueId:n,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,s,n,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},rt=async(e,t,r)=>{try{const r=Q(),o=p.v4().replace(/-/g,""),s=ee(),n=e.body,a=++Qe;let l=V(n.type);if(!n||"object"==typeof(i=n)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=B(n.infile||n.options||n.data);if(!c&&!n.svg)throw G(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Je("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=tt(Ze,e,t,{id:a,uniqueId:o,type:l,body:n}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),G(4,`[export] Got an incoming HTTP request with ID ${o}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:B(n.globalOptions,!0),themeOptions:B(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ge,allowFileResources:!1,resources:B(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=z(c,d.customLogic.allowCodeExecution));const g=te(s,d);if(g.export.options=c,g.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:o},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Je("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(g,((i,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&G(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return G(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,tt(et,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ye[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const it=JSON.parse(e.readFileSync(t.join(q,"package.json"))),ot=new Date,st=[];function nt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;st.push(t),st.length>30&&st.shift()}),6e4),We.push(t),e.get("/health",((e,t)=>{const r=je(),i=st.length,o=st.reduce(((e,t)=>e+t),0)/st.length;G(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:it.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ue(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const at=new Map,lt=v();lt.disable("x-powered-by"),lt.use(f());const ct=y.memoryStorage(),pt=y({storage:ct,limits:{fieldSize:52428800}});lt.use(v.json({limit:52428800})),lt.use(v.urlencoded({extended:!0,limit:52428800})),lt.use(pt.none());const ut=e=>{e.on("clientError",(e=>{F(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{F(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{F(1,e,`[server] Socket error: ${e.message}`)}))}))},ht=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(lt);ut(e),e.listen(r.port,r.host),at.set(r.port,e),G(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){G(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},lt);ut(e),e.listen(r.ssl.port,r.host),at.set(r.ssl.port,e),G(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ke(lt,r.rateLimiting),lt.use(v.static(t.posix.join(q,"public"))),nt(lt),(e=>{e.post("/",rt),e.post("/:filename",rt)})(lt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(q,"public","index.html"))}))})(lt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=$.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Je("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Je("No new version supplied.",400);try{await de(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(lt),(e=>{e.use(Xe),e.use(ze)})(lt)}catch(e){throw new ne("[server] Could not configure and start the server.").setError(e)}},dt=()=>{G(4,"[server] Closing all servers.");for(const[e,t]of at)t.close((()=>{G(4,`[server] Closed server on port: ${e}.`)}))};var gt={startServer:ht,closeServers:dt,getServers:()=>at,enableRateLimiting:e=>Ke(lt,e),getExpress:()=>v,getApp:()=>lt,use:(e,...t)=>{lt.use(e,...t)},get:(e,...t)=>{lt.get(e,...t)},post:(e,...t)=>{lt.post(e,...t)}};const mt=async e=>{await Promise.allSettled([Be(),dt(),Pe()]),process.exit(e)};var ft={server:gt,startServer:ht,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ge=J(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&M(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(G(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{G(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGTERM",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGHUP",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("uncaughtException",(async(e,t)=>{F(1,e,`The ${t} error.`),await mt(1)}))),await ue(e),await Ne({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Fe(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Pe()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await Pe()}catch(e){throw new ne("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,setOptions:(t,r)=>(r?.length&&(Z=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),re(x,Z),Z=ie(x),t&&(Z=te(Z,t,L)),r?.length&&(Z=function(e,t,r){let i=!1;for(let o=0;o(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(G(2,`[config] Missing value for the '${s}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&K();return e}(Z,r,x)),Z),shutdownCleanUp:mt,log:G,logWithStack:F,setLogLevel:D,enableFileLogging:M,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=_[r]?_[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,s)=>{let n=0,a=[];for(const e of s)R[e]=R[e].map((t=>({...t,section:e}))),a=[...a,...R[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=oe(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){F(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(q,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(q+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:K};module.exports=ft; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9icm93c2VyLmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9jaGFydC5qcyIsIi4uL2xpYi9zYW5pdGl6ZS5qcyIsIi4uL2xpYi9pbnRlcnZhbHMuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvcmVzb3VyY2VfcmVsZWFzZS5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFBvc3NpYmxlIG5hbWVzIGZvciBIaWdoY2hhcnRzIHNjcmlwdHNcclxuZXhwb3J0IGNvbnN0IHNjcmlwdHNOYW1lcyA9IHtcclxuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICBtb2R1bGVzOiBbXHJcbiAgICAnc3RvY2snLFxyXG4gICAgJ21hcCcsXHJcbiAgICAnZ2FudHQnLFxyXG4gICAgJ2V4cG9ydGluZycsXHJcbiAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICdib29zdCcsXHJcbiAgICAnZGF0YScsXHJcbiAgICAnZGF0YS10b29scycsXHJcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAnaGVhdG1hcCcsXHJcbiAgICAndGlsZW1hcCcsXHJcbiAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgJ3RpbWVsaW5lJyxcclxuICAgICd0cmVlbWFwJyxcclxuICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICdkcmlsbGRvd24nLFxyXG4gICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgJ2J1bGxldCcsXHJcbiAgICAnZnVubmVsJyxcclxuICAgICdmdW5uZWwzZCcsXHJcbiAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAncHlyYW1pZDNkJyxcclxuICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgJ3BhcmV0bycsXHJcbiAgICAncGF0dGVybi1maWxsJyxcclxuICAgICdwaWN0b3JpYWwnLFxyXG4gICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAnc2Fua2V5JyxcclxuICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICdzdG9jay10b29scycsXHJcbiAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgJ3N1bmJ1cnN0JyxcclxuICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgJ3Zhcml3aWRlJyxcclxuICAgICd2ZWN0b3InLFxyXG4gICAgJ3Zlbm4nLFxyXG4gICAgJ3dpbmRiYXJiJyxcclxuICAgICd3b3JkY2xvdWQnLFxyXG4gICAgJ3hyYW5nZScsXHJcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICdkcmFnLXBhbmVzJyxcclxuICAgICdkZWJ1Z2dlcicsXHJcbiAgICAnZHVtYmJlbGwnLFxyXG4gICAgJ2xvbGxpcG9wJyxcclxuICAgICdjeWxpbmRlcicsXHJcbiAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICdkb3RwbG90JyxcclxuICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICdoZWlraW5hc2hpJyxcclxuICAgICdmbG93bWFwJ1xyXG4gIF0sXHJcbiAgaW5kaWNhdG9yczogWydpbmRpY2F0b3JzLWFsbCddXHJcbn07XHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMjUwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZGVidWc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGRlYnVnIG1vZGUgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGVhZGxlc3MnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5oZWFkbGVzcy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkZXZ0b29scycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRldnRvb2xzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvQ29uc29sZScsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuc2xvd01vLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlYnVnZ2luZ1BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJlcy50ZXh0ID0gZGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIHNvdXJjZVBhdGhcclxuKSA9PiB7XHJcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XHJcbiAgY29uc3QgaGNWZXJzaW9uID0gdmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIXZlcnNpb24gPyAnJyA6IGAke3ZlcnNpb259L2A7XHJcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259JHtjfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2NkblVSTH0ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcclxuICAgICAgICAgIChpKSA9PiBgJHtjZG5VUkx9c3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgcHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PiB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xyXG4gICAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG4gIH1cclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBoaWdoY2hhcnRzLCBzZXJ2ZXIgfSA9IG9wdGlvbnM7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xyXG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0cztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNyZWF0ZSA9IGFzeW5jIChwdXBwZXRlZXJBcmdzKSA9PiB7XHJcbiAgY29uc3QgYWxsQXJncyA9IFsuLi5taW5pbWFsQXJncywgLi4uKHB1cHBldGVlckFyZ3MgfHwgW10pXTtcclxuXHJcbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWcgfSA9IGdldE9wdGlvbnMoKS5kZWJ1ZztcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nLFxyXG4gICAgYXJnczogYWxsQXJncyxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IGFzeW5jICgpID0+IHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBicm93c2VyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uaXNDb25uZWN0ZWQoKSkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgZ2V0LFxyXG4gIGNsb3NlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT5cclxuICBwYWdlLnBkZih7XHJcbiAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcclxuICAgIHdpZHRoLFxyXG4gICAgZW5jb2RpbmdcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XHJcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cclxuICovXHJcbmNvbnN0IHNldEFzQ29uZmlnID0gKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PlxyXG4gIHBhZ2UuZXZhbHVhdGUoXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIChjaGFydCwgb3B0aW9ucykgPT4gd2luZG93LnRyaWdnZXJFeHBvcnQoY2hhcnQsIG9wdGlvbnMpLFxyXG4gICAgY2hhcnQsXHJcbiAgICBvcHRpb25zXHJcbiAgKTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAqIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICovXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xyXG4gIGNvbnN0IGNsZWFySW5qZWN0ZWQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gICAgZm9yIChjb25zdCByZXMgb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcclxuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcclxuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4ubGlua3NUb1JlbW92ZVxyXG4gICAgICBdKSB7XHJcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIEZvcmNlIGEgckFGXHJcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3B1cHBldGVlci9wdXBwZXRlZXIvaXNzdWVzLzc1MDdcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge30pKTtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoZCkgPT4gKHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGQpLCBkaXNwbGF5RXJyb3JzKTtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgICBjb25zdCByZXNvdXJjZXMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcztcclxuICAgIGlmIChyZXNvdXJjZXMpIHtcclxuICAgICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgICBpZiAocmVzb3VyY2VzLmpzKSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKFxyXG4gICAgICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgICAgICA/IHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2V4cG9ydF0gVGhlIEpTIGZpbGUgJHtmaWxlfSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplXHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLFxyXG4gICAgICAgICAgKGVsZW1lbnQsIHNjYWxlKSA9PiAoe1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodDogZWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlLFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoOiBlbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZVxyXG4gICAgICAgICAgfSksXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICAgICAgKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHZpZXdwb3J0IGZvciB0aGUgZmlyc3QgdGltZVxyXG4gICAgLy8gTk9URTogdGhlIGNhbGwgdG8gc2V0Vmlld3BvcnQgaXMgZXhwZW5zaXZlIC0gY2FuIHdlIGdldCBhd2F5IHdpdGggb25seVxyXG4gICAgLy8gY2FsbGluZyBpdCBvbmNlLCBlLmcuIG1vdmluZyB0aGlzIG9uZSBpbnRvIHRoZSBpc1NWRyBjb25kaXRpb24gYmVsb3c/XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIGEgem9vbSBjYWxsYmFjayBmb3IgdGhlIG5leHQgZXZhbHVhdGUgY2FsbFxyXG4gICAgY29uc3Qgem9vbUNhbGxiYWNrID0gaXNTVkdcclxuICAgICAgPyAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgIChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG4gICAgICAgIH1cclxuICAgICAgOiAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcclxuICAgICAgICB9O1xyXG5cclxuICAgIC8vIFNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSh6b29tQ2FsbGJhY2ssIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IGhlaWdodCwgd2lkdGgsIHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgaWYgKCFpc1NWRykge1xyXG4gICAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcclxuICAgICAgICBoZWlnaHQ6IE1hdGgucm91bmQoaGVpZ2h0KSxcclxuICAgICAgICBkZXZpY2VTY2FsZUZhY3RvcjogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgZGF0YTtcclxuICAgIC8vIFJBU1RFUklaQVRJT05cclxuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgIC8vIFNWR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUG9vbCBzdGF0aXN0aWNzXHJcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcclxuICBwZXJmb3JtZWRFeHBvcnRzOiAwLFxyXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXHJcbiAgc3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIEN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbmxldCBwdXBwZXRlZXJBcmdzO1xyXG5cclxuY29uc3QgZmFjdG9yeSA9IHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlciBwYWdlIGZvciB0aGUgZXhwb3J0IHBvb2wuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxyXG4gICAqIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWwgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XHJcbiAgICogcGFnZS5cclxuICAgKi9cclxuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgIGxldCBwYWdlID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XHJcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBwYWdlID0gYXdhaXQgYnJvd3Nlck5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG4gICAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICAgIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XHJcbiAgICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICBhd2FpdCBjbGVhclBhZ2Uod29ya2VySGFuZGxlLnBhZ2UsIHRydWUpO1xyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6ICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBUaGUgbmV3ZXN0IHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBicm93c2VyIGNyZWF0aW9uXHJcbiAgcHVwcGV0ZWVyQXJncyA9IGNvbmZpZy5wdXBwZXRlZXJBcmdzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICBpblVzZTogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZ0FjcXVpcmU6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4IH0gPSBwb29sO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGF2YWlsYWJsZTogJHtwb29sLm51bUZyZWUoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjcXVpcmVkOiAke3Bvb2wubnVtVXNlZCgpfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGNhbGxlcnMgd2FpdGluZyB0byBhY3F1aXJlIGEgcmVzb3VyY2U6ICR7cG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKX0uYFxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcclxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgKTtcclxuXHJcbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICA6IGluZm8ucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGNoYXJ0IGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGNhbGN1bGF0ZWQgaGVpZ2h0LCB3aWR0aCxcclxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpbmRDaGFydFNpemUgPSAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcclxuXHJcbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxyXG4gIGxldCBzY2FsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uc2NhbGUgfHxcclxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0U2NhbGUgfHxcclxuICAgIDE7XHJcblxyXG4gIC8vIHRoZSBzY2FsZSBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjEgYW5kIGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xyXG5cclxuICAvLyB3ZSB3YW50IHRvIHJvdW5kIHRoZSBudW1iZXJzIGxpa2UgMC4yMzIzNCAtPiAwLjIzXHJcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XHJcblxyXG4gIC8vIEZpbmQgY2hhcnQgc2l6ZSBhbmQgc2NhbGVcclxuICBjb25zdCBzaXplID0ge1xyXG4gICAgaGVpZ2h0OlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgICA0MDAsXHJcbiAgICB3aWR0aDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcclxuICAgICAgNjAwLFxyXG4gICAgc2NhbGVcclxuICB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBweCBhbmQgJVxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG4gIHJldHVybiBzaXplO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXHJcbiAqIGNvbXBsZXRpb24gb3IgZXJyb3IuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlZC5cclxuICovXHJcbmNvbnN0IGRvRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMsIGNoYXJ0SnNvbiwgZW5kQ2FsbGJhY2ssIHN2ZykgPT4ge1xyXG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkID1cclxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcclxuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgIDogYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zID0gb3B0aW9ucy5jdXN0b21Mb2dpYyA9IHt9O1xyXG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XHJcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBQcm9jZXNzIHJlc291cmNlc1xyXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcclxuICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVzb3VyY2VzLFxyXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcclxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXHJcbiAgLy8gcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC4gUHJpb3JpdGl6ZWQgc2hvdWxkIGJlIHRoZSBzY29wZWRcclxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxyXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcclxuICAgICAgLy8gdGhlc2Ugc2V0dGluZ3MuXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYFxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cclxuICBpZiAoY2hhcnRKc29uKSB7XHJcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcuZW5hYmxlZCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBleHBvcnRPcHRpb25zLmNvbnN0ciB8fCAnY2hhcnQnO1xyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGdsb2JhbCBhbmQgdGhlbWUgb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMgJiYgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnJHtvcHRpb25zTmFtZX0nIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgdHJ5IHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjdXN0b21Db2RlJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xyXG4gIGlmIChcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcclxuICApIHtcclxuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxyXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xyXG4gICAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTaXplIHNlYXJjaFxyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAuLi5maW5kQ2hhcnRTaXplKG9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHRyeSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcclxuICAgICAgZXhwb3J0T3B0aW9ucy5zdHJJbmogfHwgY2hhcnRKc29uIHx8IHN2ZyxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgKTtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhmYWxzZSwgcmVzdWx0KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXHJcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxyXG4gKiBlbnN1cmluZyBhIGNsZWFuIGFuZCBmb3JtYXR0ZWQgaW5wdXQuIFRoZSByZXN1bHRpbmcgc3RyaW5nIGlzIHNhdmVkIGFzXHJcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcclxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXHJcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxyXG4gKiB0byBiZSBpbmplY3RlZC5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZFxyXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cclxuICovXHJcbmNvbnN0IGRvU3RyYWlnaHRJbmplY3QgPSAob3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICB0cnkge1xyXG4gICAgbGV0IHN0ckluajtcclxuICAgIGxldCBpbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gVHJ5IHRvIHN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHN0ckluaiA9IGluc3RyLnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcnKS50cmltKCk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xyXG4gICAgaWYgKHN0cklualtzdHJJbmoubGVuZ3RoIC0gMV0gPT09ICc7Jykge1xyXG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxyXG4gKiBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZy5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcclxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0QXNTdHJpbmcgPSAoc3RyaW5nVG9FeHBvcnQsIG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XHJcblxyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDBcclxuICApIHtcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2ssIHN0cmluZ1RvRXhwb3J0KTtcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cclxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XHJcblxyXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxyXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHZhbHVlIG9mIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcclxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZmluZENoYXJ0U2l6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqKi9cclxuXHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cclxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcclxuICogb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD4uLi48L3NjcmlwdD4gdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcclxuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZEludGVydmFsLFxyXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcclxuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIGlmICghYXBwKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cclxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xyXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsSW50ZXJ2YWxzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBPdGhlclxyXG4gIHNldE9wdGlvbnMsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsInNldFBhZ2VDb250ZW50IiwicGFnZSIsInNldENvbnRlbnQiLCJhZGRTY3JpcHRUYWciLCJldmFsdWF0ZSIsInNldHVwSGlnaGNoYXJ0cyIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsIl9kaXNwbGF5RXJyb3JzIiwiaW5uZXJIVE1MIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsImJvZHkiLCJuZXdQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiX19iYXNlZGlyIiwic2V0QXNDb25maWciLCJjaGFydCIsInRyaWdnZXJFeHBvcnQiLCJwdXBwZXRlZXJFeHBvcnQiLCJpbmplY3RlZFJlc291cmNlcyIsImNsZWFySW5qZWN0ZWQiLCJkaXNwb3NlIiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJyZW1vdmUiLCJleHBvcnRPcHRpb25zIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwiZGlzcGxheUVycm9ycyIsImRlYnVnZ2VyIiwiaXNTVkciLCJkIiwic3ZnVGVtcGxhdGUiLCJzdHJJbmoiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJhZGRTdHlsZVRhZyIsInNpemUiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiSGlnaGNoYXJ0cyIsImNoYXJ0cyIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic3RhdHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJleHBvcnRGcm9tU3ZnQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInB1cHBldGVlckFyZ3MiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwiYWxsQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInJlc291cmNlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJpc0Nvbm5lY3RlZCIsImJyb3dzZXJDbG9zZSIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwiYXZhaWxhYmxlIiwiaW5Vc2UiLCJwZW5kaW5nQWNxdWlyZSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsImV4cG9ydGluZyIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJlbmFibGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsImludGVydmFsSWRzIiwiY2xlYXJBbGxJbnRlcnZhbHMiLCJjbGVhckludGVydmFsIiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxIiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0Q29kZSIsInN0YXR1cyIsImpzb24iLCJyYXRlTGltaXQiLCJhcHAiLCJsaW1pdENvbmZpZyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJyZXF1ZXN0IiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJIdHRwRXJyb3IiLCJzZXRTdGF0dXMiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RvcENvdW50ZXIiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluZGV4IiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwiY29kZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwic2V0T3B0aW9ucyIsInVzZXJPcHRpb25zIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicHJvcCIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiI2d0JBZU8sTUFBTUEsRUFBZSxDQUMxQkMsS0FBTSxDQUFDLGFBQWMsa0JBQW1CLGlCQUN4Q0MsUUFBUyxDQUNQLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsY0FDQSx1QkFDQSxnQkFDQSx1QkFDQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index a9298704..c3d93740 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as m from"url";import{fileURLToPath as g}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as w}from"uuid";import b from"node:path";import E from"puppeteer";import{randomBytes as T}from"node:crypto";import{JSDOM as S}from"jsdom";import x from"dompurify";import R from"cors";import k from"express";import L from"multer";import _ from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},I={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},C={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:I.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:I.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:I.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:I.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:I.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:I.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${I.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${I.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:I.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:I.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:I.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:I.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:I.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:I.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:I.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:I.server.host.value},{type:"number",name:"port",message:"Server port",initial:I.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:I.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:I.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:I.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:I.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:I.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:I.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:I.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:I.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:I.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:I.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:I.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:I.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:I.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:I.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:I.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:I.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:I.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:I.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:I.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:I.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:I.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:I.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:I.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:I.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:I.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:I.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:I.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:I.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:I.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:I.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:I.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:I.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:I.other.noLogo.value}]},A=["options","globalOptions","themeOptions","resources","payload"],N={},P=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?P(o,`${t}.${r}`):(N[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(N[o.legacyName]=`${t}.${r}`.substring(1)))}}))};P(I),u.config();const $=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),H=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),j=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),G=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),M=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),F=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:$(O.core),HIGHCHARTS_MODULE_SCRIPTS:$(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:$(O.indicators),HIGHCHARTS_FORCE_FETCH:H(),HIGHCHARTS_CACHE_PATH:U(),HIGHCHARTS_ADMIN_TOKEN:U(),EXPORT_TYPE:j(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:j(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:G(),EXPORT_DEFAULT_WIDTH:G(),EXPORT_DEFAULT_SCALE:G(),EXPORT_RASTERIZATION_TIMEOUT:M(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:H(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:H(),SERVER_ENABLE:H(),SERVER_HOST:U(),SERVER_PORT:G(),SERVER_BENCHMARKING:H(),SERVER_PROXY_HOST:U(),SERVER_PROXY_PORT:G(),SERVER_PROXY_TIMEOUT:M(),SERVER_RATE_LIMITING_ENABLE:H(),SERVER_RATE_LIMITING_MAX_REQUESTS:M(),SERVER_RATE_LIMITING_WINDOW:M(),SERVER_RATE_LIMITING_DELAY:M(),SERVER_RATE_LIMITING_TRUST_PROXY:H(),SERVER_RATE_LIMITING_SKIP_KEY:U(),SERVER_RATE_LIMITING_SKIP_TOKEN:U(),SERVER_SSL_ENABLE:H(),SERVER_SSL_FORCE:H(),SERVER_SSL_PORT:G(),SERVER_SSL_CERT_PATH:U(),POOL_MIN_WORKERS:M(),POOL_MAX_WORKERS:M(),POOL_WORK_LIMIT:G(),POOL_ACQUIRE_TIMEOUT:M(),POOL_CREATE_TIMEOUT:M(),POOL_DESTROY_TIMEOUT:M(),POOL_IDLE_TIMEOUT:M(),POOL_CREATE_RETRY_INTERVAL:M(),POOL_REAPER_INTERVAL:M(),POOL_BENCHMARKING:H(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:U(),LOGGING_DEST:U(),UI_ENABLE:H(),UI_ROUTE:U(),OTHER_NODE_ENV:j(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:H(),OTHER_NO_LOGO:H()}).partial().parse(process.env),D=["red","yellow","blue","gray","green"];let V={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:D[0]},{title:"warning",color:D[1]},{title:"notice",color:D[2]},{title:"verbose",color:D[3]},{title:"benchmark",color:D[4]}],listeners:[]};for(const[e,t]of Object.entries(I.logging))V[e]=t.value;const W=(e,i)=>{V.toFile&&(V.pathCreated||(!t(V.dest)&&r(V.dest),V.pathCreated=!0),o(`${V.dest}${V.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),V.toFile=!1)})))},q=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=V;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;V.listeners.forEach((e=>{e(s,r.join(" "))})),V.toConsole&&console.log.apply(void 0,[s.toString()[V.levelsDesc[t-1].color]].concat(r)),W(r,s)},X=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=V;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];V.toConsole&&console.log.apply(void 0,[n.toString()[V.levelsDesc[e-1].color]].concat([o[D[e-1]],"\n",a])),V.listeners.forEach((e=>{e(n,l.join(" "))})),W(l,n)},K=e=>{e>=0&&e<=V.levelsDesc.length&&(V.level=e)},J=(e,t)=>{if(V={...V,dest:e||V.dest,file:t||V.file,toFile:!0},0===V.dest.length)return q(1,"[logger] File logging initialization: no path supplied.");V.dest.endsWith("/")||(V.dest+="/")},B=g(new URL("../.",import.meta.url)),z=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},Y=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=Q(i(e,"utf8"))}catch(e){return X(2,e,"[cli] No resources found.")}else o=Q(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):q(3,"[cli] No resources found.")};function Q(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Z=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Z(e[r]));return t},ee=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function te(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(I).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(I[t]))})),console.log("\n")}const re=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,oe=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&oe(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ie=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let se={};const ne=()=>se,ae=(e,t,r=[])=>{const o=Z(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:ae(o[e],s,r);var i;return o};function le(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?le(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in F&&void 0!==F[i.envLink]&&(i.value=F[i.envLink]))}))}function ce(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ce(o);return t}function pe(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=pe(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function he(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ue extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const de={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},me=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ge=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),q(4,`[cache] Fetching script - ${e}.js`);const i=await he(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ue(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return q(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},fe=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||de.cdnURL;q(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return de.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new ue("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:F.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>ge(`${e}`,l,i,!0))),...t.map((e=>ge(`${e}`,l,i))),...r.map((e=>ge(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),de.hcVersion=me(de),n(r,de.sources),a}catch(e){throw new ue("[cache] Unable to update the local Highcharts cache.").setError(e)}},ve=async e=>{const{highcharts:o,server:s}=e,a=l(B,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)q(3,"[cache] Fetching and caching Highcharts dependencies."),c=await fe(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(q(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(q(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return q(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await fe(o,s.proxy,h):(q(3,"[cache] Dependency cache is up to date, proceeding."),de.sources=i(h,"utf8"),c=t.modules,de.hcVersion=me(de))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};de.activeManifest=r,q(3,"[cache] Writing a new manifest.");try{n(l(B,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new ue("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},ye=()=>l(B,ne().highcharts.cachePath);var we=async e=>{const t=ne();t?.highcharts&&(t.highcharts.version=e),await ve(t)},be=()=>de,Ee=()=>de.hcVersion;const Te=T(64).toString("base64url"),Se=b.join("tmp",`puppeteer-${Te}`),xe=[`--user-data-dir=${b.join(Se,"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"],Re=m.fileURLToPath(new URL(".",import.meta.url)),ke=e.readFileSync(Re+"/../templates/template.html","utf8");let Le;const _e=async e=>{await e.setContent(ke),await e.addScriptTag({path:`${ye()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Oe=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await _e(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){X(2,e,"[browser] Could not clear the content of the page.")}},Ie=async()=>{if(!Le)return!1;const e=await Le.newPage();return await e.setCacheEnabled(!1),await _e(e),e};const Ce=m.fileURLToPath(new URL(".",import.meta.url)),Ae=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ne=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{q(4,"[export] Determining export path.");const n=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=n?.options?.chart?.displayErrors&&be().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(q(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else q(4,"[export] Treating as config."),n.strInj?await Ae(e,{chart:{height:n.height,width:n.width}},r):(t.chart.height=n.height,t.chart.width=n.width,await Ae(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&o.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");o.push(await e.addScriptTag(r?{content:i(t,"utf8")}:{url:t}))}catch(e){X(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let t=p.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")?o.push(await e.addStyleTag({url:i})):r.customLogic.allowFileResources&&o.push(await e.addStyleTag({path:a.join(Ce,i)})));o.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const h=c?await e.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||n.height),d=Math.ceil(h?.chartWidth||n.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)});const m=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(m,parseFloat(n.scale));const{height:g,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(g),deviceScaleFactor:parseFloat(n.scale)}),"svg"===n.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))w=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ue("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:v,y:y},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new ue(`[export] Unsupported output format ${n.type}.`);w=await((e,t,r,o)=>e.pdf({height:t+1,width:r,encoding:o}))(e,u,d,"base64")}return await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await s(e),w}catch(t){return await s(e),t}};const Pe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let $e,He={},je=!1;const Ue={create:async()=>{let e=!1;const t=w(),r=(new Date).getTime();try{if(e=await Ie(),!e||e.isClosed())throw new ue("The page is invalid or closed.");q(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ue("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(He.workLimit/2))}},validate:async e=>He.workLimit&&++e.workCount>He.workLimit?(q(3,`[pool] Worker failed validation: exceeded work limit (limit is ${He.workLimit}).`),!1):(await Oe(e.page,!0),!0),destroy:e=>{q(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Ge=async e=>{if(He=e&&e.pool?{...e.pool}:{},$e=e.puppeteerArgs,await(async e=>{const t=[...xe,...e||[]];if(!Le){let e=0;const r=async()=>{try{q(3,`[browser] Attempting to get a browser instance (try ${++e}).`),Le=await E.launch({headless:"new",args:t,userDataDir:"./tmp/",handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1})}catch(t){if(X(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;q(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r()}catch(e){throw new ue("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!Le)throw new ue("[browser] Cannot find a browser to open.")}return Le})($e),q(3,`[pool] Initializing pool with workers: min ${He.minWorkers}, max ${He.maxWorkers}.`),je)return q(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(He.minWorkers)>parseInt(He.maxWorkers)&&(He.minWorkers=He.maxWorkers);try{je=new y({...Ue,min:parseInt(He.minWorkers),max:parseInt(He.maxWorkers),acquireTimeoutMillis:He.acquireTimeout,createTimeoutMillis:He.createTimeout,destroyTimeoutMillis:He.destroyTimeout,idleTimeoutMillis:He.idleTimeout,createRetryIntervalMillis:He.createRetryInterval,reapIntervalMillis:He.reaperInterval,propagateCreateError:!1}),je.on("release",(async e=>{await Oe(e.page,!1),q(4,`[pool] Releasing a worker with ID ${e.id}.`)})),je.on("destroySuccess",((e,t)=>{q(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{je.release(e)})),q(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ue("[pool] Could not create the pool of workers.").setError(e)}};async function Me(){if(q(3,"[pool] Killing pool with all workers and closing browser."),je){for(const e of je.used)je.release(e.resource);je.destroyed||(await je.destroy(),q(4,"[browser] Destroyed the pool of resources."))}await(async()=>{Le?.isConnected()&&await Le.close(),q(4,"[browser] Closed the browser.")})()}const Fe=async(e,t)=>{let r;try{if(q(4,"[pool] Work received, starting to process."),++Pe.exportAttempts,He.benchmarking&&De(),!je)throw new ue("Work received, but pool has not been started.");try{q(4,"[pool] Acquiring a worker handle.");const e=ie();r=await je.acquire().promise,t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ue("Error encountered when acquiring an available entry.").setError(e)}if(q(4,"[pool] Acquired a worker handle."),!r.page)throw new ue("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();q(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const i=ie(),s=await Ne(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await Ie()),new ue("Error encountered during export.").setError(s);t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${i()}ms.`),je.release(r);const n=(new Date).getTime()-o;return Pe.timeSpent+=n,Pe.spentAverage=Pe.timeSpent/++Pe.performedExports,q(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++Pe.droppedExports,r&&je.release(r),new ue(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function De(){const{min:e,max:t}=je;q(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),q(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),q(5,`[pool] The number of resources that are currently available: ${je.numFree()}.`),q(5,`[pool] The number of resources that are currently acquired: ${je.numUsed()}.`),q(5,`[pool] The number of callers waiting to acquire a resource: ${je.numPendingAcquires()}.`)}var Ve=()=>({min:je.min,max:je.max,available:je.numFree(),inUse:je.numUsed(),pendingAcquire:je.numPendingAcquires()}),We=()=>Pe;let qe=!1;const Xe=async(e,t)=>{q(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Z(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=ae(t,e,A),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ne()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{q(4,"[chart] Attempting to export from a SVG input.");const e=ze(function(e){const t=new S("").window;return x(t).sanitize(e)}(r.payload.svg),r,t);return++Pe.exportFromSvgAttempts,e}catch(e){return t(new ue("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return q(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new ue("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return q(4,"[chart] Attempting to export from a raw input."),re(r.customLogic?.allowCodeExecution)?Be(r,t):"string"==typeof o.instr?ze(o.instr.trim(),r,t):Je(r,o.instr||o.options,t)}catch(e){return t(new ue("[chart] Error loading raw input.").setError(e))}return t(new ue("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ke=e=>{const{chart:t,exporting:r}=e.export?.options||Q(e.export?.instr),o=Q(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Je=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:qe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=Y(e.customLogic.resources,re(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=Y(t,re(e.customLogic.allowFileResources))}catch(e){X(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new ue("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=z(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=Q(i(s[e],"utf8"),!0):s[e]=Q(s[e],!0))}catch(t){s[e]={},X(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=oe(n.customCode,n.allowFileResources)}catch(e){X(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,X(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ke(e)};try{return r(!1,await Fe(s.strInj||t||o,e))}catch(e){return r(e)}},Be=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=ee(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Je(e,!1,t)}catch(r){return t(new ue(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},ze=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return q(4,"[chart] Parsing input as SVG."),Je(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Je(t,o,r)}catch(e){return re(o)?Be(t,r):r(new ue("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Ye=[],Qe=()=>{q(4,"[server] Clearing all registered intervals.");for(const e of Ye)clearInterval(e)},Ze=(e,t,r,o)=>{X(1,e),"development"!==F.OTHER_NODE_ENV&&delete e.stack,o(e)},et=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var tt=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=_({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(q(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),q(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class rt extends ue{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const ot={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let it=0;const st=[],nt=[],at=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},lt=async(e,t,r)=>{try{const r=ie(),i=w().replace(/-/g,""),s=ne(),n=e.body,a=++it;let l=z(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new rt("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=Q(n.infile||n.options||n.data);if(!c&&!n.svg)throw q(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new rt("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=at(st,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),q(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:Q(n.globalOptions,!0),themeOptions:Q(n.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:Q(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=ee(c,u.customLogic.allowCodeExecution));const d=ae(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new rt("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Xe(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&q(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return q(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new rt(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,at(nt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ot[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const ct=JSON.parse(i(l(B,"package.json"))),pt=new Date,ht=[];function ut(e){if(!e)return!1;var t;t=setInterval((()=>{const e=We(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ht.push(t),ht.length>30&&ht.shift()}),6e4),Ye.push(t),e.get("/health",((e,t)=>{const r=We(),o=ht.length,i=ht.reduce(((e,t)=>e+t),0)/ht.length;q(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:pt,uptime:Math.floor(((new Date).getTime()-pt.getTime())/1e3/60)+" minutes",version:ct.version,highchartsVersion:Ee(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ve(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const dt=new Map,mt=k();mt.disable("x-powered-by"),mt.use(R());const gt=L.memoryStorage(),ft=L({storage:gt,limits:{fieldSize:52428800}});mt.use(k.json({limit:52428800})),mt.use(k.urlencoded({extended:!0,limit:52428800})),mt.use(ft.none());const vt=e=>{e.on("clientError",(e=>{X(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{X(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{X(1,e,`[server] Socket error: ${e.message}`)}))}))},yt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(mt);vt(t),t.listen(e.port,e.host),dt.set(e.port,t),q(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){q(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},mt);vt(o),o.listen(e.ssl.port,e.host),dt.set(e.ssl.port,o),q(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&tt(mt,e.rateLimiting),mt.use(k.static(c.join(B,"public"))),ut(mt),(e=>{e.post("/",lt),e.post("/:filename",lt)})(mt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(B,"public","index.html"))}))})(mt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=F.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new rt("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new rt("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new rt("No new version supplied.",400);try{await we(i)}catch(e){throw new rt(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Ee(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(mt),(e=>{e.use(Ze),e.use(et)})(mt)}catch(e){throw new ue("[server] Could not configure and start the server.").setError(e)}},wt=()=>{q(4,"[server] Closing all servers.");for(const[e,t]of dt)t.close((()=>{q(4,`[server] Closed server on port: ${e}.`)}))};var bt={startServer:yt,closeServers:wt,getServers:()=>dt,enableRateLimiting:e=>tt(mt,e),getExpress:()=>k,getApp:()=>mt,use:(e,...t)=>{mt.use(e,...t)},get:(e,...t)=>{mt.get(e,...t)},post:(e,...t)=>{mt.post(e,...t)}};const Et=async e=>{await Promise.allSettled([Qe(),wt(),Me()]),process.exit(e)};var Tt={server:bt,startServer:yt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=re(t),(e=>{K(e&&parseInt(e.level)),e&&e.dest&&J(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(q(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{q(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGTERM",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGHUP",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("uncaughtException",(async(e,t)=>{X(1,e,`The ${t} error.`),await Et(1)}))),await ve(e),await Ge({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Xe(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await Me()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Xe({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await Me()}catch(e){throw new ue("[chart] Error encountered during batch export.").setError(e)}},startExport:Xe,setOptions:(e,t)=>(t?.length&&(se=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){X(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),le(I,se),se=ce(I),e&&(se=ae(se,e,A)),t?.length&&(se=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=re(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(q(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&te();return e}(se,t,I)),se),shutdownCleanUp:Et,log:q,logWithStack:X,setLogLevel:K,enableFileLogging:J,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=N[r]?N[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(C).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)C[e]=C[e].map((t=>({...t,section:e}))),n=[...n,...C[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=pe(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){X(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(B,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(B+"/msg/startup.msg").toString().bold.yellow,`v${t}`)},printUsage:te};export{Tt as default}; +import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as m from"url";import{fileURLToPath as g}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"node:path";import E from"puppeteer";import{randomBytes as T}from"node:crypto";import{JSDOM as S}from"jsdom";import x from"dompurify";import R from"cors";import L from"express";import _ from"multer";import k from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},I={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!1,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:250,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},C={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:I.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:I.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:I.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:I.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:I.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:I.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${I.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${I.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:I.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:I.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:I.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:I.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:I.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:I.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:I.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:I.server.host.value},{type:"number",name:"port",message:"Server port",initial:I.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:I.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:I.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:I.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:I.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:I.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:I.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:I.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:I.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:I.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:I.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:I.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:I.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:I.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:I.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:I.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:I.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:I.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:I.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:I.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:I.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:I.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:I.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:I.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:I.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:I.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:I.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:I.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:I.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:I.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:I.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:I.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:I.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:I.other.noLogo.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:I.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:I.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:I.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:I.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:I.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:I.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:I.debug.debuggingPort.value}]},A=["options","globalOptions","themeOptions","resources","payload"],N={},P=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?P(o,`${t}.${r}`):(N[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(N[o.legacyName]=`${t}.${r}`.substring(1)))}}))};P(I),u.config();const $=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),H=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),U=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),G=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),D=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),j=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),M=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:$(O.core),HIGHCHARTS_MODULE_SCRIPTS:$(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:$(O.indicators),HIGHCHARTS_FORCE_FETCH:H(),HIGHCHARTS_CACHE_PATH:G(),HIGHCHARTS_ADMIN_TOKEN:G(),EXPORT_TYPE:U(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:U(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:D(),EXPORT_DEFAULT_WIDTH:D(),EXPORT_DEFAULT_SCALE:D(),EXPORT_RASTERIZATION_TIMEOUT:j(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:H(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:H(),SERVER_ENABLE:H(),SERVER_HOST:G(),SERVER_PORT:D(),SERVER_BENCHMARKING:H(),SERVER_PROXY_HOST:G(),SERVER_PROXY_PORT:D(),SERVER_PROXY_TIMEOUT:j(),SERVER_RATE_LIMITING_ENABLE:H(),SERVER_RATE_LIMITING_MAX_REQUESTS:j(),SERVER_RATE_LIMITING_WINDOW:j(),SERVER_RATE_LIMITING_DELAY:j(),SERVER_RATE_LIMITING_TRUST_PROXY:H(),SERVER_RATE_LIMITING_SKIP_KEY:G(),SERVER_RATE_LIMITING_SKIP_TOKEN:G(),SERVER_SSL_ENABLE:H(),SERVER_SSL_FORCE:H(),SERVER_SSL_PORT:D(),SERVER_SSL_CERT_PATH:G(),POOL_MIN_WORKERS:j(),POOL_MAX_WORKERS:j(),POOL_WORK_LIMIT:D(),POOL_ACQUIRE_TIMEOUT:j(),POOL_CREATE_TIMEOUT:j(),POOL_DESTROY_TIMEOUT:j(),POOL_IDLE_TIMEOUT:j(),POOL_CREATE_RETRY_INTERVAL:j(),POOL_REAPER_INTERVAL:j(),POOL_BENCHMARKING:H(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:G(),LOGGING_DEST:G(),UI_ENABLE:H(),UI_ROUTE:G(),OTHER_NODE_ENV:U(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:H(),OTHER_NO_LOGO:H(),DEBUG_ENABLE:H(),DEBUG_HEADLESS:H(),DEBUG_DEVTOOLS:H(),DEBUG_LISTEN_TO_CONSOLE:H(),DEBUG_DUMPIO:H(),DEBUG_SLOW_MO:j(),DEBUG_DEBUGGING_PORT:D()}).partial().parse(process.env),F=["red","yellow","blue","gray","green"];let V={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:F[0]},{title:"warning",color:F[1]},{title:"notice",color:F[2]},{title:"verbose",color:F[3]},{title:"benchmark",color:F[4]}],listeners:[]};for(const[e,t]of Object.entries(I.logging))V[e]=t.value;const W=(e,i)=>{V.toFile&&(V.pathCreated||(!t(V.dest)&&r(V.dest),V.pathCreated=!0),o(`${V.dest}${V.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),V.toFile=!1)})))},q=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=V;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;V.listeners.forEach((e=>{e(s,r.join(" "))})),V.toConsole&&console.log.apply(void 0,[s.toString()[V.levelsDesc[t-1].color]].concat(r)),W(r,s)},B=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=V;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];V.toConsole&&console.log.apply(void 0,[n.toString()[V.levelsDesc[e-1].color]].concat([o[F[e-1]],"\n",a])),V.listeners.forEach((e=>{e(n,l.join(" "))})),W(l,n)},X=e=>{e>=0&&e<=V.levelsDesc.length&&(V.level=e)},K=(e,t)=>{if(V={...V,dest:e||V.dest,file:t||V.file,toFile:!0},0===V.dest.length)return q(1,"[logger] File logging initialization: no path supplied.");V.dest.endsWith("/")||(V.dest+="/")},J=g(new URL("../.",import.meta.url)),z=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},Y=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=Q(i(e,"utf8"))}catch(e){return B(2,e,"[cli] No resources found.")}else o=Q(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):q(3,"[cli] No resources found.")};function Q(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Z=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Z(e[r]));return t},ee=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function te(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(I).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(I[t]))})),console.log("\n")}const re=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,oe=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&oe(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ie=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let se={};const ne=()=>se,ae=(e,t,r=[])=>{const o=Z(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:ae(o[e],s,r);var i;return o};function le(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?le(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in M&&void 0!==M[i.envLink]&&(i.value=M[i.envLink]))}))}function ce(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ce(o);return t}function pe(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=pe(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function he(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ue extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const de={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},me=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ge=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),q(4,`[cache] Fetching script - ${e}.js`);const i=await he(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ue(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return q(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},fe=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||de.cdnURL;q(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return de.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new ue("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:M.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>ge(`${e}`,l,i,!0))),...t.map((e=>ge(`${e}`,l,i))),...r.map((e=>ge(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),de.hcVersion=me(de),n(r,de.sources),a}catch(e){throw new ue("[cache] Unable to update the local Highcharts cache.").setError(e)}},ve=async e=>{const{highcharts:o,server:s}=e,a=l(J,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)q(3,"[cache] Fetching and caching Highcharts dependencies."),c=await fe(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(q(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(q(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return q(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await fe(o,s.proxy,h):(q(3,"[cache] Dependency cache is up to date, proceeding."),de.sources=i(h,"utf8"),c=t.modules,de.hcVersion=me(de))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};de.activeManifest=r,q(3,"[cache] Writing a new manifest.");try{n(l(J,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new ue("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},ye=()=>l(J,ne().highcharts.cachePath);var be=async e=>{const t=ne();t?.highcharts&&(t.highcharts.version=e),await ve(t)},we=()=>de,Ee=()=>de.hcVersion;const Te=T(64).toString("base64url"),Se=w.join("tmp",`puppeteer-${Te}`),xe=[`--user-data-dir=${w.join(Se,"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"],Re=m.fileURLToPath(new URL(".",import.meta.url)),Le=e.readFileSync(Re+"/../templates/template.html","utf8");let _e;const ke=async e=>{await e.setContent(Le),await e.addScriptTag({path:`${ye()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Oe=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ke(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){B(2,e,"[browser] Could not clear the content of the page.")}},Ie=async()=>{if(!_e)return!1;const e=await _e.newPage();return await e.setCacheEnabled(!1),await ke(e),e};const Ce=m.fileURLToPath(new URL(".",import.meta.url)),Ae=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ne=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{q(4,"[export] Determining export path.");const n=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=n?.options?.chart?.displayErrors&&we().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(q(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else q(4,"[export] Treating as config."),n.strInj?await Ae(e,{chart:{height:n.height,width:n.width}},r):(t.chart.height=n.height,t.chart.width=n.width,await Ae(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&o.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");o.push(await e.addScriptTag(r?{content:i(t,"utf8")}:{url:t}))}catch(e){B(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let t=p.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")?o.push(await e.addStyleTag({url:i})):r.customLogic.allowFileResources&&o.push(await e.addStyleTag({path:a.join(Ce,i)})));o.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const h=c?await e.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||n.height),d=Math.ceil(h?.chartWidth||n.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)});const m=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(m,parseFloat(n.scale));const{height:g,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let b;if(c||await e.setViewport({width:Math.round(f),height:Math.round(g),deviceScaleFactor:parseFloat(n.scale)}),"svg"===n.type)b=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))b=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ue("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:v,y:y},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new ue(`[export] Unsupported output format ${n.type}.`);b=await((e,t,r,o)=>e.pdf({height:t+1,width:r,encoding:o}))(e,u,d,"base64")}return await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await s(e),b}catch(t){return await s(e),t}};const Pe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let $e,He={},Ue=!1;const Ge={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Ie(),!e||e.isClosed())throw new ue("The page is invalid or closed.");q(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ue("Error encountered when creating a new page.").setError(e)}const{debug:o}=ne();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(He.workLimit/2))}},validate:async e=>He.workLimit&&++e.workCount>He.workLimit?(q(3,`[pool] Worker failed validation: exceeded work limit (limit is ${He.workLimit}).`),!1):(await Oe(e.page,!0),!0),destroy:e=>{q(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},De=async e=>{if(He=e&&e.pool?{...e.pool}:{},$e=e.puppeteerArgs,await(async e=>{const t=[...xe,...e||[]],{enable:r,...o}=ne().debug,i={headless:"new",userDataDir:"./tmp/",args:t,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,...r&&o};if(!_e){let e=0;const t=async()=>{try{q(3,`[browser] Attempting to get a browser instance (try ${++e}).`),_e=await E.launch(i)}catch(r){if(B(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;q(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t()}catch(e){throw new ue("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!_e)throw new ue("[browser] Cannot find a browser to open.")}return _e})($e),q(3,`[pool] Initializing pool with workers: min ${He.minWorkers}, max ${He.maxWorkers}.`),Ue)return q(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(He.minWorkers)>parseInt(He.maxWorkers)&&(He.minWorkers=He.maxWorkers);try{Ue=new y({...Ge,min:parseInt(He.minWorkers),max:parseInt(He.maxWorkers),acquireTimeoutMillis:He.acquireTimeout,createTimeoutMillis:He.createTimeout,destroyTimeoutMillis:He.destroyTimeout,idleTimeoutMillis:He.idleTimeout,createRetryIntervalMillis:He.createRetryInterval,reapIntervalMillis:He.reaperInterval,propagateCreateError:!1}),Ue.on("release",(async e=>{await Oe(e.page,!1),q(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ue.on("destroySuccess",((e,t)=>{q(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ue.release(e)})),q(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ue("[pool] Could not create the pool of workers.").setError(e)}};async function je(){if(q(3,"[pool] Killing pool with all workers and closing browser."),Ue){for(const e of Ue.used)Ue.release(e.resource);Ue.destroyed||(await Ue.destroy(),q(4,"[browser] Destroyed the pool of resources."))}await(async()=>{_e?.isConnected()&&await _e.close(),q(4,"[browser] Closed the browser.")})()}const Me=async(e,t)=>{let r;try{if(q(4,"[pool] Work received, starting to process."),++Pe.exportAttempts,He.benchmarking&&Fe(),!Ue)throw new ue("Work received, but pool has not been started.");try{q(4,"[pool] Acquiring a worker handle.");const e=ie();r=await Ue.acquire().promise,t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ue("Error encountered when acquiring an available entry.").setError(e)}if(q(4,"[pool] Acquired a worker handle."),!r.page)throw new ue("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();q(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const i=ie(),s=await Ne(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await Ie()),new ue("Error encountered during export.").setError(s);t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${i()}ms.`),Ue.release(r);const n=(new Date).getTime()-o;return Pe.timeSpent+=n,Pe.spentAverage=Pe.timeSpent/++Pe.performedExports,q(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++Pe.droppedExports,r&&Ue.release(r),new ue(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Fe(){const{min:e,max:t}=Ue;q(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),q(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),q(5,`[pool] The number of resources that are currently available: ${Ue.numFree()}.`),q(5,`[pool] The number of resources that are currently acquired: ${Ue.numUsed()}.`),q(5,`[pool] The number of callers waiting to acquire a resource: ${Ue.numPendingAcquires()}.`)}var Ve=()=>({min:Ue.min,max:Ue.max,available:Ue.numFree(),inUse:Ue.numUsed(),pendingAcquire:Ue.numPendingAcquires()}),We=()=>Pe;let qe=!1;const Be=async(e,t)=>{q(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Z(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=ae(t,e,A),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ne()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{q(4,"[chart] Attempting to export from a SVG input.");const e=ze(function(e){const t=new S("").window;return x(t).sanitize(e)}(r.payload.svg),r,t);return++Pe.exportFromSvgAttempts,e}catch(e){return t(new ue("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return q(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new ue("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return q(4,"[chart] Attempting to export from a raw input."),re(r.customLogic?.allowCodeExecution)?Je(r,t):"string"==typeof o.instr?ze(o.instr.trim(),r,t):Ke(r,o.instr||o.options,t)}catch(e){return t(new ue("[chart] Error loading raw input.").setError(e))}return t(new ue("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Xe=e=>{const{chart:t,exporting:r}=e.export?.options||Q(e.export?.instr),o=Q(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ke=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:qe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=Y(e.customLogic.resources,re(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=Y(t,re(e.customLogic.allowFileResources))}catch(e){B(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new ue("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=z(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=Q(i(s[e],"utf8"),!0):s[e]=Q(s[e],!0))}catch(t){s[e]={},B(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=oe(n.customCode,n.allowFileResources)}catch(e){B(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,B(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Xe(e)};try{return r(!1,await Me(s.strInj||t||o,e))}catch(e){return r(e)}},Je=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=ee(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ke(e,!1,t)}catch(r){return t(new ue(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},ze=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return q(4,"[chart] Parsing input as SVG."),Ke(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ke(t,o,r)}catch(e){return re(o)?Je(t,r):r(new ue("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Ye=[],Qe=()=>{q(4,"[server] Clearing all registered intervals.");for(const e of Ye)clearInterval(e)},Ze=(e,t,r,o)=>{B(1,e),"development"!==M.OTHER_NODE_ENV&&delete e.stack,o(e)},et=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var tt=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=k({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(q(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),q(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class rt extends ue{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const ot={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let it=0;const st=[],nt=[],at=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},lt=async(e,t,r)=>{try{const r=ie(),i=b().replace(/-/g,""),s=ne(),n=e.body,a=++it;let l=z(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new rt("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=Q(n.infile||n.options||n.data);if(!c&&!n.svg)throw q(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new rt("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=at(st,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),q(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:Q(n.globalOptions,!0),themeOptions:Q(n.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:Q(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=ee(c,u.customLogic.allowCodeExecution));const d=ae(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new rt("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Be(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&q(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return q(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new rt(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,at(nt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ot[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const ct=JSON.parse(i(l(J,"package.json"))),pt=new Date,ht=[];function ut(e){if(!e)return!1;var t;t=setInterval((()=>{const e=We(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ht.push(t),ht.length>30&&ht.shift()}),6e4),Ye.push(t),e.get("/health",((e,t)=>{const r=We(),o=ht.length,i=ht.reduce(((e,t)=>e+t),0)/ht.length;q(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:pt,uptime:Math.floor(((new Date).getTime()-pt.getTime())/1e3/60)+" minutes",version:ct.version,highchartsVersion:Ee(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ve(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const dt=new Map,mt=L();mt.disable("x-powered-by"),mt.use(R());const gt=_.memoryStorage(),ft=_({storage:gt,limits:{fieldSize:52428800}});mt.use(L.json({limit:52428800})),mt.use(L.urlencoded({extended:!0,limit:52428800})),mt.use(ft.none());const vt=e=>{e.on("clientError",(e=>{B(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{B(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{B(1,e,`[server] Socket error: ${e.message}`)}))}))},yt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(mt);vt(t),t.listen(e.port,e.host),dt.set(e.port,t),q(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){q(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},mt);vt(o),o.listen(e.ssl.port,e.host),dt.set(e.ssl.port,o),q(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&tt(mt,e.rateLimiting),mt.use(L.static(c.join(J,"public"))),ut(mt),(e=>{e.post("/",lt),e.post("/:filename",lt)})(mt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(J,"public","index.html"))}))})(mt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=M.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new rt("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new rt("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new rt("No new version supplied.",400);try{await be(i)}catch(e){throw new rt(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Ee(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(mt),(e=>{e.use(Ze),e.use(et)})(mt)}catch(e){throw new ue("[server] Could not configure and start the server.").setError(e)}},bt=()=>{q(4,"[server] Closing all servers.");for(const[e,t]of dt)t.close((()=>{q(4,`[server] Closed server on port: ${e}.`)}))};var wt={startServer:yt,closeServers:bt,getServers:()=>dt,enableRateLimiting:e=>tt(mt,e),getExpress:()=>L,getApp:()=>mt,use:(e,...t)=>{mt.use(e,...t)},get:(e,...t)=>{mt.get(e,...t)},post:(e,...t)=>{mt.post(e,...t)}};const Et=async e=>{await Promise.allSettled([Qe(),bt(),je()]),process.exit(e)};var Tt={server:wt,startServer:yt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=re(t),(e=>{X(e&&parseInt(e.level)),e&&e.dest&&K(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(q(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{q(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGTERM",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGHUP",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("uncaughtException",(async(e,t)=>{B(1,e,`The ${t} error.`),await Et(1)}))),await ve(e),await De({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Be(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await je()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Be({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await je()}catch(e){throw new ue("[chart] Error encountered during batch export.").setError(e)}},startExport:Be,setOptions:(e,t)=>(t?.length&&(se=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){B(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),le(I,se),se=ce(I),e&&(se=ae(se,e,A)),t?.length&&(se=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=re(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(q(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&te();return e}(se,t,I)),se),shutdownCleanUp:Et,log:q,logWithStack:B,setLogLevel:X,enableFileLogging:K,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=N[r]?N[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(C).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)C[e]=C[e].map((t=>({...t,section:e}))),n=[...n,...C[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=pe(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){B(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(J,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(J+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:te};export{Tt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 1206dabc..7c3426d7 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/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}`\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\nimport path from 'node:path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\n// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328\r\n// Not ideal - leaves trash in the FS\r\nimport { randomBytes } from 'node:crypto';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst RANDOM_PID = randomBytes(64).toString('base64url');\r\nconst PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`);\r\nconst DATA_DIR = path.join(PUPPETEER_DIR, 'profile');\r\n\r\n// The minimal args to speed up the browser\r\nconst minimalArgs = [\r\n `--user-data-dir=${DATA_DIR}`,\r\n '--autoplay-policy=user-gesture-required',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=AudioServiceOutOfProcess',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--ignore-gpu-blacklist',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--use-mock-keychain'\r\n];\r\n\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nconst setPageContent = async (page) => {\r\n await page.setContent(template);\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => window.setupHighcharts());\r\n\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error

${error.toString()}`\r\n );\r\n });\r\n};\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport const clearPage = async (page, hardReset = false) => {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank');\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport const newPage = async () => {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n return page;\r\n};\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport const create = async (puppeteerArgs) => {\r\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch({\r\n headless: 'new',\r\n args: allArgs,\r\n userDataDir: './tmp/',\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false\r\n });\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n};\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport const get = async () => {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n\r\n return browser;\r\n};\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport const close = async () => {\r\n // Close the browser when connnected\r\n if (browser?.isConnected()) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n};\r\n\r\nexport default {\r\n newPage,\r\n clearPage,\r\n get,\r\n close\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = (page, height, width, encoding) =>\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options) =>\r\n page.evaluate(\r\n // eslint-disable-next-line no-undef\r\n (chart, options) => window.triggerExport(chart, options),\r\n chart,\r\n options\r\n );\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const res of injectedResources) {\r\n await res.dispose();\r\n }\r\n\r\n // Reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Force a rAF\r\n // See https://github.com/puppeteer/puppeteer/issues/7507\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => requestAnimationFrame(() => {}));\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart));\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedResources.push(\r\n await page.addScriptTag({\r\n content: resources.js\r\n })\r\n );\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n try {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedResources.push(\r\n await page.addScriptTag(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n )\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The JS file ${file} cannot be loaded.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Load CSS\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n url: cssImportPath\r\n })\r\n );\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n path: path.join(__basedir, cssImportPath)\r\n })\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n })\r\n );\r\n }\r\n }\r\n\r\n // Get the real chart size\r\n const size = isSVG\r\n ? await page.$eval(\r\n '#chart-container svg:first-of-type',\r\n (element, scale) => ({\r\n chartHeight: element.height.baseVal.value * scale,\r\n chartWidth: element.width.baseVal.value * scale\r\n }),\r\n parseFloat(exportOptions.scale)\r\n )\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\r\n\r\n // Set the viewport for the first time\r\n // NOTE: the call to setViewport is expensive - can we get away with only\r\n // calling it once, e.g. moving this one into the isSVG condition below?\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n // Prepare a zoom callback for the next evaluate call\r\n const zoomCallback = isSVG\r\n ? // In case of SVG the zoom must be set directly for body\r\n (scale) => {\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n }\r\n : // No need for such scale manipulation in case of other types of exports\r\n () => {\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n };\r\n\r\n // Set the zoom accordingly\r\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\r\n\r\n // Get the clip region for the page\r\n const { height, width, x, y } = await getClipRegion(page);\r\n\r\n if (!isSVG) {\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n width: Math.round(width),\r\n height: Math.round(height),\r\n deviceScaleFactor: parseFloat(exportOptions.scale)\r\n });\r\n }\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Destroy old charts after the export is done\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n });\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Custom puppeteer arguments\r\nlet puppeteerArgs;\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n await clearPage(workerHandle.page, true);\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // The newest puppeteer arguments for the browser creation\r\n puppeteerArgs = config.puppeteerArgs;\r\n\r\n // Create a browser instance\r\n await createBrowser(puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n const acquireCounter = measureTime();\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when acquiring an available entry.'\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError('Error encountered during export.').setError(\r\n result\r\n );\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n available: pool.numFree(),\r\n inUse: pool.numUsed(),\r\n pendingAcquire: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max } = pool;\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently available: ${pool.numFree()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently acquired: ${pool.numUsed()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of callers waiting to acquire a resource: ${pool.numPendingAcquires()}.`\r\n );\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input);\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer?.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","setPageContent","page","setContent","addScriptTag","evaluate","setupHighcharts","$eval","element","errorMessage","_displayErrors","innerHTML","clearPage","hardReset","goto","document","body","newPage","setCacheEnabled","__basedir","setAsConfig","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportOptions","requestAnimationFrame","displayErrors","debugger","isSVG","d","svgTemplate","strInj","js","push","content","isLocal","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","Highcharts","charts","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","_resolve","setTimeout","createImage","pdf","createPDF","oldCharts","oldChart","destroy","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","puppeteerArgs","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","close","initPool","allArgs","tryCount","open","launch","headless","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","isConnected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","prop","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"srBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBACA,uBACA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,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,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,GACPC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 250,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\nimport path from 'node:path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\n// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328\r\n// Not ideal - leaves trash in the FS\r\nimport { randomBytes } from 'node:crypto';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst RANDOM_PID = randomBytes(64).toString('base64url');\r\nconst PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`);\r\nconst DATA_DIR = path.join(PUPPETEER_DIR, 'profile');\r\n\r\n// The minimal args to speed up the browser\r\nconst minimalArgs = [\r\n `--user-data-dir=${DATA_DIR}`,\r\n '--autoplay-policy=user-gesture-required',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=AudioServiceOutOfProcess',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--ignore-gpu-blacklist',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--use-mock-keychain'\r\n];\r\n\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nconst setPageContent = async (page) => {\r\n await page.setContent(template);\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => window.setupHighcharts());\r\n\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error

${error.toString()}`\r\n );\r\n });\r\n};\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport const clearPage = async (page, hardReset = false) => {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank');\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport const newPage = async () => {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n};\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport const create = async (puppeteerArgs) => {\r\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\r\n\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'new',\r\n userDataDir: './tmp/',\r\n args: allArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n};\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport const get = async () => {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n\r\n return browser;\r\n};\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport const close = async () => {\r\n // Close the browser when connnected\r\n if (browser?.isConnected()) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n};\r\n\r\nexport default {\r\n newPage,\r\n clearPage,\r\n get,\r\n close\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = (page, height, width, encoding) =>\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options) =>\r\n page.evaluate(\r\n // eslint-disable-next-line no-undef\r\n (chart, options) => window.triggerExport(chart, options),\r\n chart,\r\n options\r\n );\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const res of injectedResources) {\r\n await res.dispose();\r\n }\r\n\r\n // Reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Force a rAF\r\n // See https://github.com/puppeteer/puppeteer/issues/7507\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => requestAnimationFrame(() => {}));\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart));\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedResources.push(\r\n await page.addScriptTag({\r\n content: resources.js\r\n })\r\n );\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n try {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedResources.push(\r\n await page.addScriptTag(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n )\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The JS file ${file} cannot be loaded.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Load CSS\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n url: cssImportPath\r\n })\r\n );\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n path: path.join(__basedir, cssImportPath)\r\n })\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n })\r\n );\r\n }\r\n }\r\n\r\n // Get the real chart size\r\n const size = isSVG\r\n ? await page.$eval(\r\n '#chart-container svg:first-of-type',\r\n (element, scale) => ({\r\n chartHeight: element.height.baseVal.value * scale,\r\n chartWidth: element.width.baseVal.value * scale\r\n }),\r\n parseFloat(exportOptions.scale)\r\n )\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\r\n\r\n // Set the viewport for the first time\r\n // NOTE: the call to setViewport is expensive - can we get away with only\r\n // calling it once, e.g. moving this one into the isSVG condition below?\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n // Prepare a zoom callback for the next evaluate call\r\n const zoomCallback = isSVG\r\n ? // In case of SVG the zoom must be set directly for body\r\n (scale) => {\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n }\r\n : // No need for such scale manipulation in case of other types of exports\r\n () => {\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n };\r\n\r\n // Set the zoom accordingly\r\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\r\n\r\n // Get the clip region for the page\r\n const { height, width, x, y } = await getClipRegion(page);\r\n\r\n if (!isSVG) {\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n width: Math.round(width),\r\n height: Math.round(height),\r\n deviceScaleFactor: parseFloat(exportOptions.scale)\r\n });\r\n }\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Destroy old charts after the export is done\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n });\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Custom puppeteer arguments\r\nlet puppeteerArgs;\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n await clearPage(workerHandle.page, true);\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // The newest puppeteer arguments for the browser creation\r\n puppeteerArgs = config.puppeteerArgs;\r\n\r\n // Create a browser instance\r\n await createBrowser(puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n const acquireCounter = measureTime();\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when acquiring an available entry.'\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError('Error encountered during export.').setError(\r\n result\r\n );\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n available: pool.numFree(),\r\n inUse: pool.numUsed(),\r\n pendingAcquire: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max } = pool;\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently available: ${pool.numFree()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently acquired: ${pool.numUsed()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of callers waiting to acquire a resource: ${pool.numPendingAcquires()}.`\r\n );\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input);\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer?.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","setPageContent","page","setContent","addScriptTag","evaluate","setupHighcharts","$eval","element","errorMessage","_displayErrors","innerHTML","clearPage","hardReset","goto","document","body","newPage","setCacheEnabled","__basedir","setAsConfig","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportOptions","requestAnimationFrame","displayErrors","debugger","isSVG","d","svgTemplate","strInj","js","push","content","isLocal","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","Highcharts","charts","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","_resolve","setTimeout","createImage","pdf","createPDF","oldCharts","oldChart","destroy","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","puppeteerArgs","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","close","initPool","allArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","isConnected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","prop","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"srBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBACA,uBACA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,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,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,GACPC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,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"} \ No newline at end of file diff --git a/lib/browser.js b/lib/browser.js index 2907497f..8dfac86f 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -23,6 +23,7 @@ import puppeteer from 'puppeteer'; import { randomBytes } from 'node:crypto'; import { getCachePath } from './cache.js'; +import { getOptions } from './config.js'; import { log, logWithStack } from './logger.js'; import ExportError from './errors/ExportError.js'; @@ -169,6 +170,7 @@ export const newPage = async () => { // Set the content await setPageContent(page); + return page; }; @@ -186,6 +188,18 @@ export const newPage = async () => { export const create = async (puppeteerArgs) => { const allArgs = [...minimalArgs, ...(puppeteerArgs || [])]; + // Get the debug options + const { enable: enabledDebug, ...debug } = getOptions().debug; + const launchOptions = { + headless: 'new', + userDataDir: './tmp/', + args: allArgs, + handleSIGINT: false, + handleSIGTERM: false, + handleSIGHUP: false, + ...(enabledDebug && debug) + }; + // Create a browser if (!browser) { let tryCount = 0; @@ -196,14 +210,7 @@ export const create = async (puppeteerArgs) => { 3, `[browser] Attempting to get a browser instance (try ${++tryCount}).` ); - browser = await puppeteer.launch({ - headless: 'new', - args: allArgs, - userDataDir: './tmp/', - handleSIGINT: false, - handleSIGTERM: false, - handleSIGHUP: false - }); + browser = await puppeteer.launch(launchOptions); } catch (error) { logWithStack( 1, diff --git a/lib/envs.js b/lib/envs.js index 78985d6d..dfdbd6cb 100644 --- a/lib/envs.js +++ b/lib/envs.js @@ -202,7 +202,16 @@ export const Config = z.object({ // other OTHER_NODE_ENV: v.enum(['development', 'production', 'test']), OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(), - OTHER_NO_LOGO: v.boolean() + OTHER_NO_LOGO: v.boolean(), + + // debugger + DEBUG_ENABLE: v.boolean(), + DEBUG_HEADLESS: v.boolean(), + DEBUG_DEVTOOLS: v.boolean(), + DEBUG_LISTEN_TO_CONSOLE: v.boolean(), + DEBUG_DUMPIO: v.boolean(), + DEBUG_SLOW_MO: v.nonNegativeNum(), + DEBUG_DEBUGGING_PORT: v.positiveNum() }); export const envs = Config.partial().parse(process.env); diff --git a/lib/pool.js b/lib/pool.js index 42e3e679..87d8f6d3 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -21,6 +21,7 @@ import { newPage as browserNewPage, clearPage } from './browser.js'; +import { getOptions } from './config.js'; import puppeteerExport from './export.js'; import { log, logWithStack } from './logger.js'; import { measureTime } from './utils.js'; @@ -80,6 +81,14 @@ const factory = { ).setError(error); } + const { debug } = getOptions(); + // Set the console listener, if needed + if (debug.enable && debug.listenToConsole) { + page.on('console', (message) => { + console.log(`[debug] ${message.text()}`); + }); + } + return { id, page, diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 69e8b4bc..9dae72cd 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -565,6 +565,51 @@ export const defaultConfig = { description: 'Skip printing the logo on a startup. Will be replaced by a simple text.' } + }, + debug: { + enable: { + value: false, + type: 'boolean', + envLink: 'DEBUG_ENABLE', + cliName: 'enableDebug', + description: '.' + }, + headless: { + value: false, + type: 'boolean', + envLink: 'DEBUG_HEADLESS', + description: '.' + }, + devtools: { + value: false, + type: 'boolean', + envLink: 'DEBUG_DEVTOOLS', + description: '.' + }, + listenToConsole: { + value: false, + type: 'boolean', + envLink: 'DEBUG_LISTEN_TO_CONSOLE', + description: '.' + }, + dumpio: { + value: false, + type: 'boolean', + envLink: 'DEBUG_DUMPIO', + description: '.' + }, + slowMo: { + value: 250, + type: 'number', + envLink: 'DEBUG_SLOW_MO', + description: '.' + }, + debuggingPort: { + value: 9222, + type: 'number', + envLink: 'DEBUG_DEBUGGING_PORT', + description: '.' + } } }; @@ -931,6 +976,50 @@ export const promptsConfig = { message: 'Skip printing the logo on startup. Replaced by simple text', initial: defaultConfig.other.noLogo.value } + ], + debug: [ + { + type: 'toggle', + name: 'enable', + message: 'Enable debug mode for the browser instance', + initial: defaultConfig.debug.enable.value + }, + { + type: 'toggle', + name: 'headless', + message: '', + initial: defaultConfig.debug.headless.value + }, + { + type: 'toggle', + name: 'devtools', + message: '', + initial: defaultConfig.debug.devtools.value + }, + { + type: 'toggle', + name: 'listenToConsole', + message: '', + initial: defaultConfig.debug.listenToConsole.value + }, + { + type: 'toggle', + name: 'dumpio', + message: '', + initial: defaultConfig.debug.dumpio.value + }, + { + type: 'number', + name: 'slowMo', + message: '', + initial: defaultConfig.debug.slowMo.value + }, + { + type: 'number', + name: 'debuggingPort', + message: '', + initial: defaultConfig.debug.debuggingPort.value + } ] }; diff --git a/lib/utils.js b/lib/utils.js index 945f69f3..6823c003 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -328,7 +328,7 @@ export const printLogo = (noLogo) => { // Print the logo console.log( readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow, - `v${packageVersion}` + `v${packageVersion}\n`.bold ); }; diff --git a/msg/startup.msg b/msg/startup.msg index 658d8c6a..46f73a79 100644 --- a/msg/startup.msg +++ b/msg/startup.msg @@ -1,12 +1,12 @@ - __ ___ __ __ __ - / / / (_)___ _/ /_ _____/ /_ ____ ______/ /______ - / /_/ / / __ `/ __ \/ ___/ __ \/ __ `/ ___/ __/ ___/ - / __ / / /_/ / / / / /__/ / / / /_/ / / / /_(__ ) -/_/ /_/_/\__, /_/ /_/\___/_/ /_/\__,_/_/ \__/____/ - ____//___/ __ _____ - / ____/ ______ ____ _____/ /_ / ___/___ ______ _____ _____ - / __/ | |/_/ __ \/ __ \/ ___/ __/ \__ \/ _ \/ ___/ | / / _ \/ ___/ - / /____> =18.12.0" @@ -1278,9 +1278,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz", - "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", + "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", "cpu": [ "arm" ], @@ -1291,9 +1291,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz", - "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", + "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", "cpu": [ "arm64" ], @@ -1304,9 +1304,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz", - "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", + "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", "cpu": [ "arm64" ], @@ -1317,9 +1317,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz", - "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", + "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", "cpu": [ "x64" ], @@ -1330,9 +1330,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz", - "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", + "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", "cpu": [ "arm" ], @@ -1343,9 +1343,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz", - "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", + "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", "cpu": [ "arm" ], @@ -1356,9 +1356,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz", - "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", + "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", "cpu": [ "arm64" ], @@ -1369,9 +1369,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz", - "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", + "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", "cpu": [ "arm64" ], @@ -1382,9 +1382,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz", - "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", + "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", "cpu": [ "ppc64" ], @@ -1395,9 +1395,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz", - "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", + "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", "cpu": [ "riscv64" ], @@ -1408,9 +1408,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz", - "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", + "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", "cpu": [ "s390x" ], @@ -1421,9 +1421,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz", - "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", + "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", "cpu": [ "x64" ], @@ -1434,9 +1434,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz", - "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", + "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", "cpu": [ "x64" ], @@ -1447,9 +1447,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz", - "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", + "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", "cpu": [ "arm64" ], @@ -1460,9 +1460,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz", - "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", + "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", "cpu": [ "ia32" ], @@ -1473,9 +1473,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz", - "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", + "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", "cpu": [ "x64" ], @@ -2312,9 +2312,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001609", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", - "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "dev": true, "funding": [ { @@ -2934,9 +2934,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1262051", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1262051.tgz", - "integrity": "sha512-YJe4CT5SA8on3Spa+UDtNhEqtuV6Epwz3OZ4HQVLhlRccpZ9/PAYk0/cy/oKxFKRrZPBUPyxympQci4yWNWZ9g==" + "version": "0.0.1273771", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1273771.tgz", + "integrity": "sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==" }, "node_modules/diff-sequences": { "version": "29.6.3", @@ -2981,9 +2981,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.735", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.735.tgz", - "integrity": "sha512-pkYpvwg8VyOTQAeBqZ7jsmpCjko1Qc6We1ZtZCjRyYbT5v4AIUKDy5cQTRotQlSSZmMr8jqpEt6JtOj5k7lR7A==", + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==", "dev": true }, "node_modules/emittery": { @@ -6250,9 +6250,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -6826,15 +6826,15 @@ } }, "node_modules/puppeteer": { - "version": "22.6.5", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.6.5.tgz", - "integrity": "sha512-YuoRKGj3MxHhUwrey7vmNvU4odGdUdNsj1ee8pfcqQlLWIXfMOXZCAXh8xdzpZESHH3tCGWp2xmPZE8E6iUEWg==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.7.0.tgz", + "integrity": "sha512-s1ulKFZKW3lwWCtNu0VrRLfRaanFHxIv7F8UFYpLo8dPTZcI4wB4EAOD0sKT3SKP+1Rsjodb9WFsK78yKQ6i9Q==", "hasInstallScript": true, "dependencies": { "@puppeteer/browsers": "2.2.2", "cosmiconfig": "9.0.0", - "devtools-protocol": "0.0.1262051", - "puppeteer-core": "22.6.5" + "devtools-protocol": "0.0.1273771", + "puppeteer-core": "22.7.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -6844,14 +6844,14 @@ } }, "node_modules/puppeteer-core": { - "version": "22.6.5", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.6.5.tgz", - "integrity": "sha512-s0/5XkAWe0/dWISiljdrybjwDCHhgN31Nu/wznOZPKeikgcJtZtbvPKBz0t802XWqfSQnQDt3L6xiAE5JLlfuw==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.7.0.tgz", + "integrity": "sha512-9Q+L3VD7cfhXnxv6AqwTHsVb/+/uXENByhPrgvwQ49wvzQwtf1d6b7v6gpoG3tpRdwYjxoV1eHTD8tFahww09g==", "dependencies": { "@puppeteer/browsers": "2.2.2", "chromium-bidi": "0.5.17", "debug": "4.3.4", - "devtools-protocol": "0.0.1262051", + "devtools-protocol": "0.0.1273771", "ws": "8.16.0" }, "engines": { @@ -7120,9 +7120,9 @@ } }, "node_modules/rollup": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz", - "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", + "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -7135,22 +7135,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.3", - "@rollup/rollup-android-arm64": "4.14.3", - "@rollup/rollup-darwin-arm64": "4.14.3", - "@rollup/rollup-darwin-x64": "4.14.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.3", - "@rollup/rollup-linux-arm-musleabihf": "4.14.3", - "@rollup/rollup-linux-arm64-gnu": "4.14.3", - "@rollup/rollup-linux-arm64-musl": "4.14.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3", - "@rollup/rollup-linux-riscv64-gnu": "4.14.3", - "@rollup/rollup-linux-s390x-gnu": "4.14.3", - "@rollup/rollup-linux-x64-gnu": "4.14.3", - "@rollup/rollup-linux-x64-musl": "4.14.3", - "@rollup/rollup-win32-arm64-msvc": "4.14.3", - "@rollup/rollup-win32-ia32-msvc": "4.14.3", - "@rollup/rollup-win32-x64-msvc": "4.14.3", + "@rollup/rollup-android-arm-eabi": "4.16.4", + "@rollup/rollup-android-arm64": "4.16.4", + "@rollup/rollup-darwin-arm64": "4.16.4", + "@rollup/rollup-darwin-x64": "4.16.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", + "@rollup/rollup-linux-arm-musleabihf": "4.16.4", + "@rollup/rollup-linux-arm64-gnu": "4.16.4", + "@rollup/rollup-linux-arm64-musl": "4.16.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", + "@rollup/rollup-linux-riscv64-gnu": "4.16.4", + "@rollup/rollup-linux-s390x-gnu": "4.16.4", + "@rollup/rollup-linux-x64-gnu": "4.16.4", + "@rollup/rollup-linux-x64-musl": "4.16.4", + "@rollup/rollup-win32-arm64-msvc": "4.16.4", + "@rollup/rollup-win32-ia32-msvc": "4.16.4", + "@rollup/rollup-win32-x64-msvc": "4.16.4", "fsevents": "~2.3.2" } }, @@ -7858,9 +7858,9 @@ } }, "node_modules/terser": { - "version": "5.30.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", - "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", + "version": "5.30.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", + "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8640,9 +8640,9 @@ } }, "node_modules/zod": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.5.tgz", - "integrity": "sha512-HqnGsCdVZ2xc0qWPLdO25WnseXThh0kEYKIdV5F/hTHO75hNZFp8thxSeHhiPrHZKrFTo1SOgkAj9po5bexZlw==", + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.4.tgz", + "integrity": "sha512-/AtWOKbBgjzEYYQRNfoGKHObgfAZag6qUJX1VbHo2PRBgS+wfWagEY2mizjfyAPcGesrJOcx/wcl0L9WnVrHFw==", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 5bf7c14f..30dc7025 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "install": "node ./install.js", "prestart": "rm -rf tmp || del -rf tmp /Q && node ./node_modules/puppeteer/install.mjs", "start": "node ./bin/cli.js --enableServer 1 --logLevel 2", - "dev:start": "nodemon ./bin/cli.js --enableServer 1 --logLevel 4", + "start:debug": "node ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", + "start:dev": "nodemon ./bin/cli.js --enableServer 1 --logLevel 4", "lint": "eslint ./ --fix", "cli-tests": "node ./tests/cli/cli_test_runner.js", "cli-tests-single": "node ./tests/cli/cli_test_runner_single.js", @@ -48,7 +49,7 @@ "lint-staged": "^15.2.2", "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.14.3" + "rollup": "^4.16.4" }, "dependencies": { "colors": "1.4.0", @@ -61,10 +62,10 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.6.5", + "puppeteer": "^22.7.0", "tarn": "^3.0.2", "uuid": "^9.0.1", - "zod": "^3.22.5" + "zod": "^3.23.4" }, "lint-staged": { "*.js": "npx eslint --cache --fix", From 198880d06217697db26403211f7b5805176b05d1 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 24 Apr 2024 19:39:38 +0200 Subject: [PATCH 2/7] Added log. --- lib/browser.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/browser.js b/lib/browser.js index 8dfac86f..e3973dc4 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -231,6 +231,10 @@ export const create = async (puppeteerArgs) => { try { await open(); + // Debug mode inform + if (enabledDebug) { + log(3, `[browser] Lanuched browser in debug mode.`); + } } catch (error) { throw new ExportError( '[browser] Maximum retries to open a browser instance reached.' From eea8edf75a8f769c9e98c152b0ec2685b93a7bb1 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Thu, 9 May 2024 19:17:22 +0200 Subject: [PATCH 3/7] Performance increasing changes and other corrections. --- .env.sample | 1 + README.md | 5 +- dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/browser.js | 268 ++++++++----------- lib/envs.js | 1 + lib/export.js | 257 +++++++++--------- lib/highcharts.js | 135 ++++++++++ lib/index.js | 2 +- lib/pool.js | 83 +++--- lib/schemas/config.js | 70 ++++- lib/server/server.js | 1 + package-lock.json | 563 +++++++++++++++++----------------------- package.json | 12 +- templates/template.html | 143 ---------- 16 files changed, 728 insertions(+), 821 deletions(-) create mode 100644 lib/highcharts.js diff --git a/.env.sample b/.env.sample index eeb6b00a..256f3e37 100644 --- a/.env.sample +++ b/.env.sample @@ -71,6 +71,7 @@ UI_ROUTE = / OTHER_NODE_ENV = production OTHER_LISTEN_TO_PROCESS_EXITS = true OTHER_NO_LOGO = false +OTHER_HARD_RESET_PAGE = false # DEBUG CONFIG DEBUG_ENABLE = false diff --git a/README.md b/README.md index e87f601e..94df5d8d 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,8 @@ The format, along with its default values, is as follows (using the recommended "other": { "nodeEnv": "production", "listenToProcessExits": true, - "noLogo": false + "noLogo": false, + "hardResetPage": false } } ``` @@ -350,6 +351,7 @@ These variables are set in your environment and take precedence over options fro - `OTHER_NODE_ENV`: The type of Node.js environment. The value controls whether to include the error's stack in a response or not. Can be development or production (defaults to `production`). - `OTHER_LISTEN_TO_PROCESS_EXITS`: Decides whether or not to attach _process.exit_ handlers (defaults to `true`). - `OTHER_NO_LOGO`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). +- `OTHER_HARD_RESET_PAGE`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). ## Command Line Arguments @@ -414,6 +416,7 @@ _Available options:_ - `--nodeEnv`: The type of Node.js environment (defaults to `production`). - `--listenToProcessExits`: Decides whether or not to attach process.exit handlers (defaults to `true`). - `--noLogo`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). +- `--hardResetPage`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). # HTTP Server diff --git a/dist/index.cjs b/dist/index.cjs index 2048ac3b..c0050e71 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("node:path"),h=require("puppeteer"),d=require("node:crypto"),g=require("jsdom"),m=require("dompurify"),f=require("cors"),v=require("express"),y=require("multer"),b=require("express-rate-limit"),w="undefined"!=typeof document?document.currentScript:null;function E(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var T=E(n);const S={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},x={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:S.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:S.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:S.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!1,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:250,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},R={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:x.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:x.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:x.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:x.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:x.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:x.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${x.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${x.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:x.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:x.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:x.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:x.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:x.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:x.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:x.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:x.server.host.value},{type:"number",name:"port",message:"Server port",initial:x.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:x.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:x.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:x.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:x.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:x.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:x.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:x.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:x.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:x.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:x.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:x.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:x.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:x.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:x.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:x.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:x.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:x.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:x.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:x.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:x.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:x.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:x.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:x.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:x.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:x.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:x.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:x.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:x.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:x.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:x.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:x.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:x.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:x.other.noLogo.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:x.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:x.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:x.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:x.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:x.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:x.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:x.debug.debuggingPort.value}]},L=["options","globalOptions","themeOptions","resources","payload"],_={},k=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?k(i,`${t}.${r}`):(_[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(_[i.legacyName]=`${t}.${r}`.substring(1)))}}))};k(x),o.config();const O=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),I=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),C=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),A=()=>s.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),N=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),P=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=s.z.object({HIGHCHARTS_VERSION:s.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:s.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(S.core),HIGHCHARTS_MODULE_SCRIPTS:O(S.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(S.indicators),HIGHCHARTS_FORCE_FETCH:I(),HIGHCHARTS_CACHE_PATH:A(),HIGHCHARTS_ADMIN_TOKEN:A(),EXPORT_TYPE:C(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:C(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:N(),EXPORT_DEFAULT_WIDTH:N(),EXPORT_DEFAULT_SCALE:N(),EXPORT_RASTERIZATION_TIMEOUT:P(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:I(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:I(),SERVER_ENABLE:I(),SERVER_HOST:A(),SERVER_PORT:N(),SERVER_BENCHMARKING:I(),SERVER_PROXY_HOST:A(),SERVER_PROXY_PORT:N(),SERVER_PROXY_TIMEOUT:P(),SERVER_RATE_LIMITING_ENABLE:I(),SERVER_RATE_LIMITING_MAX_REQUESTS:P(),SERVER_RATE_LIMITING_WINDOW:P(),SERVER_RATE_LIMITING_DELAY:P(),SERVER_RATE_LIMITING_TRUST_PROXY:I(),SERVER_RATE_LIMITING_SKIP_KEY:A(),SERVER_RATE_LIMITING_SKIP_TOKEN:A(),SERVER_SSL_ENABLE:I(),SERVER_SSL_FORCE:I(),SERVER_SSL_PORT:N(),SERVER_SSL_CERT_PATH:A(),POOL_MIN_WORKERS:P(),POOL_MAX_WORKERS:P(),POOL_WORK_LIMIT:N(),POOL_ACQUIRE_TIMEOUT:P(),POOL_CREATE_TIMEOUT:P(),POOL_DESTROY_TIMEOUT:P(),POOL_IDLE_TIMEOUT:P(),POOL_CREATE_RETRY_INTERVAL:P(),POOL_REAPER_INTERVAL:P(),POOL_BENCHMARKING:I(),LOGGING_LEVEL:s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:A(),LOGGING_DEST:A(),UI_ENABLE:I(),UI_ROUTE:A(),OTHER_NODE_ENV:C(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:I(),OTHER_NO_LOGO:I(),DEBUG_ENABLE:I(),DEBUG_HEADLESS:I(),DEBUG_DEVTOOLS:I(),DEBUG_LISTEN_TO_CONSOLE:I(),DEBUG_DUMPIO:I(),DEBUG_SLOW_MO:P(),DEBUG_DEBUGGING_PORT:N()}).partial().parse(process.env),H=["red","yellow","blue","gray","green"];let U={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:H[0]},{title:"warning",color:H[1]},{title:"notice",color:H[2]},{title:"verbose",color:H[3]},{title:"benchmark",color:H[4]}],listeners:[]};for(const[e,t]of Object.entries(x.logging))U[e]=t.value;const j=(t,r)=>{U.toFile&&(U.pathCreated||(!e.existsSync(U.dest)&&e.mkdirSync(U.dest),U.pathCreated=!0),e.appendFile(`${U.dest}${U.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),U.toFile=!1)})))},G=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=U;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;U.listeners.forEach((e=>{e(s,r.join(" "))})),U.toConsole&&console.log.apply(void 0,[s.toString()[U.levelsDesc[t-1].color]].concat(r)),j(r,s)},F=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:s}=U;if(0===e||e>o||o>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];U.toConsole&&console.log.apply(void 0,[n.toString()[U.levelsDesc[e-1].color]].concat([i[H[e-1]],"\n",a])),U.listeners.forEach((e=>{e(n,l.join(" "))})),j(l,n)},D=e=>{e>=0&&e<=U.levelsDesc.length&&(U.level=e)},M=(e,t)=>{if(U={...U,dest:e||U.dest,file:t||U.file,toFile:!0},0===U.dest.length)return G(1,"[logger] File logging initialization: no path supplied.");U.dest.endsWith("/")||(U.dest+="/")},q=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),V=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},W=(t=!1,r)=>{const i=["js","css","files"];let o=t,s=!1;if(r&&t.endsWith(".json"))try{o=B(e.readFileSync(t,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else o=B(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):G(3,"[cli] No resources found.")};function B(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const X=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=X(e[r]));return t},z=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function K(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(x).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(x[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Y=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&Y(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},Q=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Z={};const ee=()=>Z,te=(e,t,r=[])=>{const i=X(e);for(const[e,s]of Object.entries(t))i[e]="object"!=typeof(o=s)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==s?s:i[e]:te(i[e],s,r);var o;return i};function re(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],s=t&&t[i];void 0===o.value?re(o,s,`${r}.${i}`):(void 0!==s&&(o.value=s),o.envLink in $&&void 0!==$[o.envLink]&&(o.value=$[o.envLink]))}))}function ie(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:ie(i);return t}function oe(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=oe(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function se(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class ne extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ae={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},le=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ce=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),G(4,`[cache] Fetching script - ${e}.js`);const o=await se(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new ne(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return G(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},pe=async(t,i,o)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ae.cdnURL;G(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ae.sources=await(async(e,t,i,o,s)=>{let n;const a=o.host,l=o.port;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new ne("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:$.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ce(`${e}`,c,s,!0))),...t.map((e=>ce(`${e}`,c,s))),...i.map((e=>ce(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,i,l),ae.hcVersion=le(ae),e.writeFileSync(o,ae.sources),l}catch(e){throw new ne("[cache] Unable to update the local Highcharts cache.").setError(e)}},ue=async r=>{const{highcharts:i,server:o}=r,s=t.join(q,i.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||i.forceFetch)G(3,"[cache] Fetching and caching Highcharts dependencies."),n=await pe(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:s,moduleScripts:c,indicatorScripts:p}=i,u=s.length+c.length+p.length;r.version!==i.version?(G(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(G(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return G(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await pe(i,o.proxy,l):(G(3,"[cache] Dependency cache is up to date, proceeding."),ae.sources=e.readFileSync(l,"utf8"),n=r.modules,ae.hcVersion=le(ae))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ae.activeManifest=o,G(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(q,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ne("[cache] Error writing the cache manifest.").setError(e)}})(i,n)},he=()=>t.join(q,ee().highcharts.cachePath);var de=async e=>{const t=ee();t?.highcharts&&(t.highcharts.version=e),await ue(t)},ge=()=>ae,me=()=>ae.hcVersion;const fe=d.randomBytes(64).toString("base64url"),ve=u.join("tmp",`puppeteer-${fe}`),ye=[`--user-data-dir=${u.join(ve,"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"],be=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),we=e.readFileSync(be+"/../templates/template.html","utf8");let Ee;const Te=async e=>{await e.setContent(we),await e.addScriptTag({path:`${he()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Se=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){F(2,e,"[browser] Could not clear the content of the page.")}},xe=async()=>{if(!Ee)return!1;const e=await Ee.newPage();return await e.setCacheEnabled(!1),await Te(e),e};const Re=T.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),Le=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var _e=async(r,i,o)=>{const s=[],n=async e=>{for(const e of s)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{G(4,"[export] Determining export path.");const a=o.export;await r.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&ge().activeManifest.modules.debugger;let c;if(await r.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(G(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else G(4,"[export] Treating as config."),a.strInj?await Le(r,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await Le(r,i,o));const p=o.customLogic.resources;if(p){if(p.js&&s.push(await r.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const i=!t.startsWith("http");s.push(await r.addScriptTag(i?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){F(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let e=p.css.match(/@import\s*([^;]*);/g);if(e)for(let i of e)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?s.push(await r.addStyleTag({url:i})):o.customLogic.allowFileResources&&s.push(await r.addStyleTag({path:t.join(Re,i)})));s.push(await r.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=c?await r.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),h=Math.ceil(u?.chartHeight||a.height),d=Math.ceil(u?.chartWidth||a.width);await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await r.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let b;if(c||await r.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(a.scale)}),"svg"===a.type)b=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))b=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ne("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:v,y:y},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new ne(`[export] Unsupported output format ${a.type}.`);b=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(r,h,d,"base64")}return await r.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await n(r),b}catch(e){return await n(r),e}};const ke={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe,Ie={},Ce=!1;const Ae={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await xe(),!e||e.isClosed())throw new ne("The page is invalid or closed.");G(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ne("Error encountered when creating a new page.").setError(e)}const{debug:i}=ee();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ie.workLimit/2))}},validate:async e=>Ie.workLimit&&++e.workCount>Ie.workLimit?(G(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ie.workLimit}).`),!1):(await Se(e.page,!0),!0),destroy:e=>{G(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Ne=async e=>{if(Ie=e&&e.pool?{...e.pool}:{},Oe=e.puppeteerArgs,await(async e=>{const t=[...ye,...e||[]],{enable:r,...i}=ee().debug,o={headless:"new",userDataDir:"./tmp/",args:t,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,...r&&i};if(!Ee){let e=0;const t=async()=>{try{G(3,`[browser] Attempting to get a browser instance (try ${++e}).`),Ee=await h.launch(o)}catch(r){if(F(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;G(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t()}catch(e){throw new ne("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!Ee)throw new ne("[browser] Cannot find a browser to open.")}return Ee})(Oe),G(3,`[pool] Initializing pool with workers: min ${Ie.minWorkers}, max ${Ie.maxWorkers}.`),Ce)return G(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ie.minWorkers)>parseInt(Ie.maxWorkers)&&(Ie.minWorkers=Ie.maxWorkers);try{Ce=new c.Pool({...Ae,min:parseInt(Ie.minWorkers),max:parseInt(Ie.maxWorkers),acquireTimeoutMillis:Ie.acquireTimeout,createTimeoutMillis:Ie.createTimeout,destroyTimeoutMillis:Ie.destroyTimeout,idleTimeoutMillis:Ie.idleTimeout,createRetryIntervalMillis:Ie.createRetryInterval,reapIntervalMillis:Ie.reaperInterval,propagateCreateError:!1}),Ce.on("release",(async e=>{await Se(e.page,!1),G(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ce.on("destroySuccess",((e,t)=>{G(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ce.release(e)})),G(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ne("[pool] Could not create the pool of workers.").setError(e)}};async function Pe(){if(G(3,"[pool] Killing pool with all workers and closing browser."),Ce){for(const e of Ce.used)Ce.release(e.resource);Ce.destroyed||(await Ce.destroy(),G(4,"[browser] Destroyed the pool of resources."))}await(async()=>{Ee?.isConnected()&&await Ee.close(),G(4,"[browser] Closed the browser.")})()}const $e=async(e,t)=>{let r;try{if(G(4,"[pool] Work received, starting to process."),++ke.exportAttempts,Ie.benchmarking&&He(),!Ce)throw new ne("Work received, but pool has not been started.");try{G(4,"[pool] Acquiring a worker handle.");const e=Q();r=await Ce.acquire().promise,t.server.benchmarking&&G(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ne("Error encountered when acquiring an available entry.").setError(e)}if(G(4,"[pool] Acquired a worker handle."),!r.page)throw new ne("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();G(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=Q(),s=await _e(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await xe()),new ne("Error encountered during export.").setError(s);t.server.benchmarking&&G(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Ce.release(r);const n=(new Date).getTime()-i;return ke.timeSpent+=n,ke.spentAverage=ke.timeSpent/++ke.performedExports,G(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++ke.droppedExports,r&&Ce.release(r),new ne(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=Ce;G(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),G(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),G(5,`[pool] The number of resources that are currently available: ${Ce.numFree()}.`),G(5,`[pool] The number of resources that are currently acquired: ${Ce.numUsed()}.`),G(5,`[pool] The number of callers waiting to acquire a resource: ${Ce.numPendingAcquires()}.`)}var Ue=()=>({min:Ce.min,max:Ce.max,available:Ce.numFree(),inUse:Ce.numUsed(),pendingAcquire:Ce.numPendingAcquires()}),je=()=>ke;let Ge=!1;const Fe=async(t,r)=>{G(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=X(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=te(t,e,L),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,ee()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{G(4,"[chart] Attempting to export from a SVG input.");const e=Ve(function(e){const t=new g.JSDOM("").window;return m(t).sanitize(e)}(i.payload.svg),i,r);return++ke.exportFromSvgAttempts,e}catch(e){return r(new ne("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return G(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Ve(i.export.instr.trim(),i,r)}catch(e){return r(new ne("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return G(4,"[chart] Attempting to export from a raw input."),J(i.customLogic?.allowCodeExecution)?qe(i,r):"string"==typeof o.instr?Ve(o.instr.trim(),i,r):Me(i,o.instr||o.options,r)}catch(e){return r(new ne("[chart] Error loading raw input.").setError(e))}return r(new ne("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},De=e=>{const{chart:t,exporting:r}=e.export?.options||B(e.export?.instr),i=B(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Me=async(t,r,i,o)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ge;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=W(t.customLogic.resources,J(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=W(r,J(t.customLogic.allowFileResources))}catch(e){F(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return i(new ne("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=V(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=B(e.readFileSync(s[t],"utf8"),!0):s[t]=B(s[t],!0))}catch(e){s[t]={},F(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Y(n.customCode,n.allowFileResources)}catch(e){F(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,F(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...De(t)};try{return i(!1,await $e(s.strInj||r||o,t))}catch(e){return i(e)}},qe=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=z(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Me(e,!1,t)}catch(r){return t(new ne(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ve=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return G(4,"[chart] Parsing input as SVG."),Me(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Me(t,i,r)}catch(e){return J(i)?qe(t,r):r(new ne("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},We=[],Be=()=>{G(4,"[server] Clearing all registered intervals.");for(const e of We)clearInterval(e)},Xe=(e,t,r,i)=>{F(1,e),"development"!==$.OTHER_NODE_ENV&&delete e.stack,i(e)},ze=(e,t,r,i)=>{const{statusCode:o,status:s,message:n,stack:a}=e,l=o||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ke=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=b({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(G(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),G(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends ne{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ye={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Qe=0;const Ze=[],et=[],tt=(e,t,r,i)=>{let o=!0;const{id:s,uniqueId:n,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,s,n,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},rt=async(e,t,r)=>{try{const r=Q(),o=p.v4().replace(/-/g,""),s=ee(),n=e.body,a=++Qe;let l=V(n.type);if(!n||"object"==typeof(i=n)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=B(n.infile||n.options||n.data);if(!c&&!n.svg)throw G(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Je("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=tt(Ze,e,t,{id:a,uniqueId:o,type:l,body:n}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),G(4,`[export] Got an incoming HTTP request with ID ${o}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:B(n.globalOptions,!0),themeOptions:B(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ge,allowFileResources:!1,resources:B(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=z(c,d.customLogic.allowCodeExecution));const g=te(s,d);if(g.export.options=c,g.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:o},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Je("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(g,((i,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&G(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return G(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,tt(et,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ye[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const it=JSON.parse(e.readFileSync(t.join(q,"package.json"))),ot=new Date,st=[];function nt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;st.push(t),st.length>30&&st.shift()}),6e4),We.push(t),e.get("/health",((e,t)=>{const r=je(),i=st.length,o=st.reduce(((e,t)=>e+t),0)/st.length;G(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:it.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ue(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const at=new Map,lt=v();lt.disable("x-powered-by"),lt.use(f());const ct=y.memoryStorage(),pt=y({storage:ct,limits:{fieldSize:52428800}});lt.use(v.json({limit:52428800})),lt.use(v.urlencoded({extended:!0,limit:52428800})),lt.use(pt.none());const ut=e=>{e.on("clientError",(e=>{F(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{F(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{F(1,e,`[server] Socket error: ${e.message}`)}))}))},ht=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(lt);ut(e),e.listen(r.port,r.host),at.set(r.port,e),G(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){G(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},lt);ut(e),e.listen(r.ssl.port,r.host),at.set(r.ssl.port,e),G(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ke(lt,r.rateLimiting),lt.use(v.static(t.posix.join(q,"public"))),nt(lt),(e=>{e.post("/",rt),e.post("/:filename",rt)})(lt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(q,"public","index.html"))}))})(lt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=$.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Je("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Je("No new version supplied.",400);try{await de(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(lt),(e=>{e.use(Xe),e.use(ze)})(lt)}catch(e){throw new ne("[server] Could not configure and start the server.").setError(e)}},dt=()=>{G(4,"[server] Closing all servers.");for(const[e,t]of at)t.close((()=>{G(4,`[server] Closed server on port: ${e}.`)}))};var gt={startServer:ht,closeServers:dt,getServers:()=>at,enableRateLimiting:e=>Ke(lt,e),getExpress:()=>v,getApp:()=>lt,use:(e,...t)=>{lt.use(e,...t)},get:(e,...t)=>{lt.get(e,...t)},post:(e,...t)=>{lt.post(e,...t)}};const mt=async e=>{await Promise.allSettled([Be(),dt(),Pe()]),process.exit(e)};var ft={server:gt,startServer:ht,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ge=J(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&M(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(G(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{G(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGTERM",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("SIGHUP",(async(e,t)=>{G(4,`The ${e} event with code: ${t}.`),await mt(0)})),process.on("uncaughtException",(async(e,t)=>{F(1,e,`The ${t} error.`),await mt(1)}))),await ue(e),await Ne({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Fe(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Pe()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await Pe()}catch(e){throw new ne("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,setOptions:(t,r)=>(r?.length&&(Z=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),re(x,Z),Z=ie(x),t&&(Z=te(Z,t,L)),r?.length&&(Z=function(e,t,r){let i=!1;for(let o=0;o(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(G(2,`[config] Missing value for the '${s}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&K();return e}(Z,r,x)),Z),shutdownCleanUp:mt,log:G,logWithStack:F,setLogLevel:D,enableFileLogging:M,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=_[r]?_[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,s)=>{let n=0,a=[];for(const e of s)R[e]=R[e].map((t=>({...t,section:e}))),a=[...a,...R[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=oe(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){F(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(q,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(q+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:K};module.exports=ft; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9icm93c2VyLmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9jaGFydC5qcyIsIi4uL2xpYi9zYW5pdGl6ZS5qcyIsIi4uL2xpYi9pbnRlcnZhbHMuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvcmVzb3VyY2VfcmVsZWFzZS5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFBvc3NpYmxlIG5hbWVzIGZvciBIaWdoY2hhcnRzIHNjcmlwdHNcclxuZXhwb3J0IGNvbnN0IHNjcmlwdHNOYW1lcyA9IHtcclxuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICBtb2R1bGVzOiBbXHJcbiAgICAnc3RvY2snLFxyXG4gICAgJ21hcCcsXHJcbiAgICAnZ2FudHQnLFxyXG4gICAgJ2V4cG9ydGluZycsXHJcbiAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICdib29zdCcsXHJcbiAgICAnZGF0YScsXHJcbiAgICAnZGF0YS10b29scycsXHJcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAnaGVhdG1hcCcsXHJcbiAgICAndGlsZW1hcCcsXHJcbiAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgJ3RpbWVsaW5lJyxcclxuICAgICd0cmVlbWFwJyxcclxuICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICdkcmlsbGRvd24nLFxyXG4gICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgJ2J1bGxldCcsXHJcbiAgICAnZnVubmVsJyxcclxuICAgICdmdW5uZWwzZCcsXHJcbiAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAncHlyYW1pZDNkJyxcclxuICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgJ3BhcmV0bycsXHJcbiAgICAncGF0dGVybi1maWxsJyxcclxuICAgICdwaWN0b3JpYWwnLFxyXG4gICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAnc2Fua2V5JyxcclxuICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICdzdG9jay10b29scycsXHJcbiAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgJ3N1bmJ1cnN0JyxcclxuICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgJ3Zhcml3aWRlJyxcclxuICAgICd2ZWN0b3InLFxyXG4gICAgJ3Zlbm4nLFxyXG4gICAgJ3dpbmRiYXJiJyxcclxuICAgICd3b3JkY2xvdWQnLFxyXG4gICAgJ3hyYW5nZScsXHJcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICdkcmFnLXBhbmVzJyxcclxuICAgICdkZWJ1Z2dlcicsXHJcbiAgICAnZHVtYmJlbGwnLFxyXG4gICAgJ2xvbGxpcG9wJyxcclxuICAgICdjeWxpbmRlcicsXHJcbiAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICdkb3RwbG90JyxcclxuICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICdoZWlraW5hc2hpJyxcclxuICAgICdmbG93bWFwJ1xyXG4gIF0sXHJcbiAgaW5kaWNhdG9yczogWydpbmRpY2F0b3JzLWFsbCddXHJcbn07XHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMjUwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZGVidWc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGRlYnVnIG1vZGUgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGVhZGxlc3MnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5oZWFkbGVzcy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkZXZ0b29scycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRldnRvb2xzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvQ29uc29sZScsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuc2xvd01vLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlYnVnZ2luZ1BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJlcy50ZXh0ID0gZGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIHNvdXJjZVBhdGhcclxuKSA9PiB7XHJcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XHJcbiAgY29uc3QgaGNWZXJzaW9uID0gdmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIXZlcnNpb24gPyAnJyA6IGAke3ZlcnNpb259L2A7XHJcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259JHtjfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2NkblVSTH0ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcclxuICAgICAgICAgIChpKSA9PiBgJHtjZG5VUkx9c3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgcHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PiB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xyXG4gICAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG4gIH1cclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBoaWdoY2hhcnRzLCBzZXJ2ZXIgfSA9IG9wdGlvbnM7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xyXG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0cztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNyZWF0ZSA9IGFzeW5jIChwdXBwZXRlZXJBcmdzKSA9PiB7XHJcbiAgY29uc3QgYWxsQXJncyA9IFsuLi5taW5pbWFsQXJncywgLi4uKHB1cHBldGVlckFyZ3MgfHwgW10pXTtcclxuXHJcbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWcgfSA9IGdldE9wdGlvbnMoKS5kZWJ1ZztcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nLFxyXG4gICAgYXJnczogYWxsQXJncyxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IGFzeW5jICgpID0+IHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBicm93c2VyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uaXNDb25uZWN0ZWQoKSkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgZ2V0LFxyXG4gIGNsb3NlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT5cclxuICBwYWdlLnBkZih7XHJcbiAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcclxuICAgIHdpZHRoLFxyXG4gICAgZW5jb2RpbmdcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XHJcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cclxuICovXHJcbmNvbnN0IHNldEFzQ29uZmlnID0gKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PlxyXG4gIHBhZ2UuZXZhbHVhdGUoXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIChjaGFydCwgb3B0aW9ucykgPT4gd2luZG93LnRyaWdnZXJFeHBvcnQoY2hhcnQsIG9wdGlvbnMpLFxyXG4gICAgY2hhcnQsXHJcbiAgICBvcHRpb25zXHJcbiAgKTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAqIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICovXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xyXG4gIGNvbnN0IGNsZWFySW5qZWN0ZWQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gICAgZm9yIChjb25zdCByZXMgb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcclxuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcclxuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4ubGlua3NUb1JlbW92ZVxyXG4gICAgICBdKSB7XHJcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIEZvcmNlIGEgckFGXHJcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3B1cHBldGVlci9wdXBwZXRlZXIvaXNzdWVzLzc1MDdcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge30pKTtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoZCkgPT4gKHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGQpLCBkaXNwbGF5RXJyb3JzKTtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgICBjb25zdCByZXNvdXJjZXMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcztcclxuICAgIGlmIChyZXNvdXJjZXMpIHtcclxuICAgICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgICBpZiAocmVzb3VyY2VzLmpzKSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKFxyXG4gICAgICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgICAgICA/IHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2V4cG9ydF0gVGhlIEpTIGZpbGUgJHtmaWxlfSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplXHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLFxyXG4gICAgICAgICAgKGVsZW1lbnQsIHNjYWxlKSA9PiAoe1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodDogZWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlLFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoOiBlbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZVxyXG4gICAgICAgICAgfSksXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICAgICAgKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHZpZXdwb3J0IGZvciB0aGUgZmlyc3QgdGltZVxyXG4gICAgLy8gTk9URTogdGhlIGNhbGwgdG8gc2V0Vmlld3BvcnQgaXMgZXhwZW5zaXZlIC0gY2FuIHdlIGdldCBhd2F5IHdpdGggb25seVxyXG4gICAgLy8gY2FsbGluZyBpdCBvbmNlLCBlLmcuIG1vdmluZyB0aGlzIG9uZSBpbnRvIHRoZSBpc1NWRyBjb25kaXRpb24gYmVsb3c/XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIGEgem9vbSBjYWxsYmFjayBmb3IgdGhlIG5leHQgZXZhbHVhdGUgY2FsbFxyXG4gICAgY29uc3Qgem9vbUNhbGxiYWNrID0gaXNTVkdcclxuICAgICAgPyAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgIChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG4gICAgICAgIH1cclxuICAgICAgOiAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcclxuICAgICAgICB9O1xyXG5cclxuICAgIC8vIFNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSh6b29tQ2FsbGJhY2ssIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IGhlaWdodCwgd2lkdGgsIHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgaWYgKCFpc1NWRykge1xyXG4gICAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcclxuICAgICAgICBoZWlnaHQ6IE1hdGgucm91bmQoaGVpZ2h0KSxcclxuICAgICAgICBkZXZpY2VTY2FsZUZhY3RvcjogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgZGF0YTtcclxuICAgIC8vIFJBU1RFUklaQVRJT05cclxuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgIC8vIFNWR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUG9vbCBzdGF0aXN0aWNzXHJcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcclxuICBwZXJmb3JtZWRFeHBvcnRzOiAwLFxyXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXHJcbiAgc3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIEN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbmxldCBwdXBwZXRlZXJBcmdzO1xyXG5cclxuY29uc3QgZmFjdG9yeSA9IHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlciBwYWdlIGZvciB0aGUgZXhwb3J0IHBvb2wuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxyXG4gICAqIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWwgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XHJcbiAgICogcGFnZS5cclxuICAgKi9cclxuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgIGxldCBwYWdlID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XHJcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBwYWdlID0gYXdhaXQgYnJvd3Nlck5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG4gICAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICAgIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XHJcbiAgICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICBhd2FpdCBjbGVhclBhZ2Uod29ya2VySGFuZGxlLnBhZ2UsIHRydWUpO1xyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6ICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBUaGUgbmV3ZXN0IHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBicm93c2VyIGNyZWF0aW9uXHJcbiAgcHVwcGV0ZWVyQXJncyA9IGNvbmZpZy5wdXBwZXRlZXJBcmdzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICBpblVzZTogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZ0FjcXVpcmU6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4IH0gPSBwb29sO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGF2YWlsYWJsZTogJHtwb29sLm51bUZyZWUoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjcXVpcmVkOiAke3Bvb2wubnVtVXNlZCgpfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGNhbGxlcnMgd2FpdGluZyB0byBhY3F1aXJlIGEgcmVzb3VyY2U6ICR7cG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKX0uYFxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcclxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgKTtcclxuXHJcbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICA6IGluZm8ucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGNoYXJ0IGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGNhbGN1bGF0ZWQgaGVpZ2h0LCB3aWR0aCxcclxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpbmRDaGFydFNpemUgPSAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcclxuXHJcbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxyXG4gIGxldCBzY2FsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uc2NhbGUgfHxcclxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0U2NhbGUgfHxcclxuICAgIDE7XHJcblxyXG4gIC8vIHRoZSBzY2FsZSBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjEgYW5kIGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xyXG5cclxuICAvLyB3ZSB3YW50IHRvIHJvdW5kIHRoZSBudW1iZXJzIGxpa2UgMC4yMzIzNCAtPiAwLjIzXHJcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XHJcblxyXG4gIC8vIEZpbmQgY2hhcnQgc2l6ZSBhbmQgc2NhbGVcclxuICBjb25zdCBzaXplID0ge1xyXG4gICAgaGVpZ2h0OlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgICA0MDAsXHJcbiAgICB3aWR0aDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcclxuICAgICAgNjAwLFxyXG4gICAgc2NhbGVcclxuICB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBweCBhbmQgJVxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG4gIHJldHVybiBzaXplO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXHJcbiAqIGNvbXBsZXRpb24gb3IgZXJyb3IuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlZC5cclxuICovXHJcbmNvbnN0IGRvRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMsIGNoYXJ0SnNvbiwgZW5kQ2FsbGJhY2ssIHN2ZykgPT4ge1xyXG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkID1cclxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcclxuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgIDogYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zID0gb3B0aW9ucy5jdXN0b21Mb2dpYyA9IHt9O1xyXG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XHJcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBQcm9jZXNzIHJlc291cmNlc1xyXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcclxuICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVzb3VyY2VzLFxyXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcclxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXHJcbiAgLy8gcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC4gUHJpb3JpdGl6ZWQgc2hvdWxkIGJlIHRoZSBzY29wZWRcclxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxyXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcclxuICAgICAgLy8gdGhlc2Ugc2V0dGluZ3MuXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYFxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cclxuICBpZiAoY2hhcnRKc29uKSB7XHJcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcuZW5hYmxlZCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBleHBvcnRPcHRpb25zLmNvbnN0ciB8fCAnY2hhcnQnO1xyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGdsb2JhbCBhbmQgdGhlbWUgb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMgJiYgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnJHtvcHRpb25zTmFtZX0nIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgdHJ5IHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjdXN0b21Db2RlJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xyXG4gIGlmIChcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcclxuICApIHtcclxuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxyXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xyXG4gICAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTaXplIHNlYXJjaFxyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAuLi5maW5kQ2hhcnRTaXplKG9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHRyeSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcclxuICAgICAgZXhwb3J0T3B0aW9ucy5zdHJJbmogfHwgY2hhcnRKc29uIHx8IHN2ZyxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgKTtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhmYWxzZSwgcmVzdWx0KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXHJcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxyXG4gKiBlbnN1cmluZyBhIGNsZWFuIGFuZCBmb3JtYXR0ZWQgaW5wdXQuIFRoZSByZXN1bHRpbmcgc3RyaW5nIGlzIHNhdmVkIGFzXHJcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcclxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXHJcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxyXG4gKiB0byBiZSBpbmplY3RlZC5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZFxyXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cclxuICovXHJcbmNvbnN0IGRvU3RyYWlnaHRJbmplY3QgPSAob3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICB0cnkge1xyXG4gICAgbGV0IHN0ckluajtcclxuICAgIGxldCBpbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gVHJ5IHRvIHN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHN0ckluaiA9IGluc3RyLnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcnKS50cmltKCk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xyXG4gICAgaWYgKHN0cklualtzdHJJbmoubGVuZ3RoIC0gMV0gPT09ICc7Jykge1xyXG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxyXG4gKiBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZy5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcclxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0QXNTdHJpbmcgPSAoc3RyaW5nVG9FeHBvcnQsIG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XHJcblxyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDBcclxuICApIHtcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2ssIHN0cmluZ1RvRXhwb3J0KTtcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cclxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XHJcblxyXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxyXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHZhbHVlIG9mIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcclxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZmluZENoYXJ0U2l6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqKi9cclxuXHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cclxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcclxuICogb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD4uLi48L3NjcmlwdD4gdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcclxuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZEludGVydmFsLFxyXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcclxuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIGlmICghYXBwKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cclxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xyXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsSW50ZXJ2YWxzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBPdGhlclxyXG4gIHNldE9wdGlvbnMsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsInNldFBhZ2VDb250ZW50IiwicGFnZSIsInNldENvbnRlbnQiLCJhZGRTY3JpcHRUYWciLCJldmFsdWF0ZSIsInNldHVwSGlnaGNoYXJ0cyIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsIl9kaXNwbGF5RXJyb3JzIiwiaW5uZXJIVE1MIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsImJvZHkiLCJuZXdQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiX19iYXNlZGlyIiwic2V0QXNDb25maWciLCJjaGFydCIsInRyaWdnZXJFeHBvcnQiLCJwdXBwZXRlZXJFeHBvcnQiLCJpbmplY3RlZFJlc291cmNlcyIsImNsZWFySW5qZWN0ZWQiLCJkaXNwb3NlIiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJyZW1vdmUiLCJleHBvcnRPcHRpb25zIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwiZGlzcGxheUVycm9ycyIsImRlYnVnZ2VyIiwiaXNTVkciLCJkIiwic3ZnVGVtcGxhdGUiLCJzdHJJbmoiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJhZGRTdHlsZVRhZyIsInNpemUiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiSGlnaGNoYXJ0cyIsImNoYXJ0cyIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic3RhdHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJleHBvcnRGcm9tU3ZnQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInB1cHBldGVlckFyZ3MiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwiYWxsQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInJlc291cmNlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJpc0Nvbm5lY3RlZCIsImJyb3dzZXJDbG9zZSIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwiYXZhaWxhYmxlIiwiaW5Vc2UiLCJwZW5kaW5nQWNxdWlyZSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsImV4cG9ydGluZyIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJlbmFibGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsImludGVydmFsSWRzIiwiY2xlYXJBbGxJbnRlcnZhbHMiLCJjbGVhckludGVydmFsIiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxIiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0Q29kZSIsInN0YXR1cyIsImpzb24iLCJyYXRlTGltaXQiLCJhcHAiLCJsaW1pdENvbmZpZyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJyZXF1ZXN0IiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJIdHRwRXJyb3IiLCJzZXRTdGF0dXMiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RvcENvdW50ZXIiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluZGV4IiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwiY29kZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwic2V0T3B0aW9ucyIsInVzZXJPcHRpb25zIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicHJvcCIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiI2d0JBZU8sTUFBTUEsRUFBZSxDQUMxQkMsS0FBTSxDQUFDLGFBQWMsa0JBQW1CLGlCQUN4Q0MsUUFBUyxDQUNQLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsY0FDQSx1QkFDQSxnQkFDQSx1QkFDQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVB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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(R[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(R[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),o.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=H;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=H;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([i[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else o=W(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const i=V(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:Z(i[e],n,r);var o;return i};function ee(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?ee(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in N&&void 0!==N[o.envLink]&&(o.value=N[o.envLink]))}))}function te(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:te(i);return t}function re(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=re(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function ie(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class oe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const o=await ie(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,i,o)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,i,o,n)=>{let s;const a=o.host,l=o.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...i.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,i,l),ne.hcVersion=se(ne),e.writeFileSync(o,ne.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:i,server:o}=r,n=t.join(F,i.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||i.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=i,u=n.length+c.length+p.length;r.version!==i.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(i,o.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ne.activeManifest=o,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(i,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:i,merge:o,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=o(!1,{},i()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=o(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;n(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const u=i();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await Ee(e),e}async function we(e,t=!1){try{t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Ee(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}async function Ee(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Te=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Se=(e,t,r,i)=>e.evaluate(me,t,r,i);var xe=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{U(4,"[export] Determining export path.");const a=o.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Se(r,{chart:{height:a.height,width:a.width}},o,l):(i.chart.height=a.height,i.chart.width=a.width,await Se(r,i,o,l));const p=o.customLogic.resources;if(p){const i=[];if(p.js&&i.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");i.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of i)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}i.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):o.customLogic.allowFileResources&&s.push({path:t.join(Te,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,i=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:i}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new oe("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new oe(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:i})))(r,h,d,"base64")}return await s(r),f}catch(e){return await s(r),e}};let Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new oe("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}const{debug:i}=Q();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Oe.workLimit/2))}},validate:async e=>{if(Oe.workLimit&&++e.workCount>Oe.workLimit)return U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Oe.workLimit}).`),!1;try{const{other:t}=Q();return await we(e.page,t.hardResetPage),!0}catch{return!1}},destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},ke=async e=>{if(Oe=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,i={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(i)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new oe("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Oe.minWorkers}, max ${Oe.maxWorkers}.`),Re)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Oe.minWorkers)>parseInt(Oe.maxWorkers)&&(Oe.minWorkers=Oe.maxWorkers);try{Re=new c.Pool({..._e,min:parseInt(Oe.minWorkers),max:parseInt(Oe.maxWorkers),acquireTimeoutMillis:Oe.acquireTimeout,createTimeoutMillis:Oe.createTimeout,destroyTimeoutMillis:Oe.destroyTimeout,idleTimeoutMillis:Oe.idleTimeout,createRetryIntervalMillis:Oe.createRetryInterval,reapIntervalMillis:Oe.reaperInterval,propagateCreateError:!1}),Re.on("release",(async e=>{await we(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Re.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Re.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(U(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Le.exportAttempts,Oe.benchmarking&&Ne(),!Re)throw new oe("Work received, but pool has not been started.");const i=J();try{U(4,"[pool] Acquiring a worker handle."),r=await Re.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${i()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${i()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await xe(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),Re.release(r);const a=(new Date).getTime()-o;return Le.timeSpent+=a,Le.spentAverage=Le.timeSpent/++Le.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Le.droppedExports,r&&Re.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ne(){const{min:e,max:t,all:r,available:i,used:o,pending:n}=Ae();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${i}.`),U(5,`[pool] The number of acquired resources: ${o}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Pe=Ae,He=()=>Le;let $e=!1;const Ue=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Fe(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e)}(i.payload.svg),i,r);return++Le.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Fe(i.export.instr.trim(),i,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(i.customLogic?.allowCodeExecution)?Ge(i,r):"string"==typeof o.instr?Fe(o.instr.trim(),i,r):De(i,o.instr||o.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},je=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),i=W(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},De=async(t,r,i,o)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:$e;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...je(t)};try{return i(!1,await Ce(n.strInj||r||o,t))}catch(e){return i(e)}},Ge=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=B(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,De(e,!1,t)}catch(r){return t(new oe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Fe=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),De(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return De(t,i,r)}catch(e){return z(i)?Ge(t,r):r(new oe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Me=[],qe=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Me)clearInterval(e)},We=(e,t,r,i)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,i(e)},Ve=(e,t,r,i)=>{const{statusCode:o,status:n,message:s,stack:a}=e,l=o||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Be=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=v({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),U(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Xe extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ke=0;const Je=[],Ye=[],Qe=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:s,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,s,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},Ze=async(e,t,r)=>{try{const r=J(),o=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++Ke;let l=M(s.type);if(!s||"object"==typeof(i=s)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Xe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Qe(Je,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:$e,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Xe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ue(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,Qe(Ye,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ze[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const et=JSON.parse(e.readFileSync(t.join(F,"package.json"))),tt=new Date,rt=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;rt.push(t),rt.length>30&&rt.shift()}),6e4),Me.push(t),e.get("/health",((e,t)=>{const r=He(),i=rt.length,o=rt.reduce(((e,t)=>e+t),0)/rt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:tt,uptime:Math.floor(((new Date).getTime()-tt.getTime())/1e3/60)+" minutes",version:et.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ot=new Map,nt=m();nt.disable("x-powered-by"),nt.use(g());const st=f.memoryStorage(),at=f({storage:st,limits:{fieldSize:52428800}});nt.use(m.json({limit:52428800})),nt.use(m.urlencoded({extended:!0,limit:52428800})),nt.use(at.none());const lt=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},ct=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(nt);lt(e),e.listen(r.port,r.host),ot.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},nt);lt(e),e.listen(r.ssl.port,r.host),ot.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Be(nt,r.rateLimiting),nt.use(m.static(t.posix.join(F,"public"))),it(nt),(e=>{e.post("/",Ze),e.post("/:filename",Ze)})(nt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(nt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Xe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Xe("No new version supplied.",400);try{await ue(o)}catch(e){throw new Xe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(nt),(e=>{e.use(We),e.use(Ve)})(nt)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},pt=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ot)t.close((()=>{ot.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var ut={startServer:ct,closeServers:pt,getServers:()=>ot,enableRateLimiting:e=>Be(nt,e),getExpress:()=>m,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const ht=async e=>{await Promise.allSettled([qe(),pt(),Ie()]),process.exit(e)};var dt={server:ut,startServer:ct,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,$e=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ht(1)}))),await ce(e),await ke({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ue(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Ue({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await Ie()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:Ue,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let i=!1;for(let o=0;o(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=z(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ht,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=re(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:X};module.exports=dt; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLE1lZGlhUm91dGVyLFRyYW5zbGF0ZSxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcmd1bWVudHMgYXJyYXkgdG8gc2VuZCB0byBQdXBwZXRlZXIuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNkblVSTDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZmxhZyB0byBkZXRlcm1pbmUgd2hldGhlciB0byByZWZldGNoIGFsbCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuLidcclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5LiBJdCBpcyB1c2VkIHRvIHN0b3JlIHRoZSBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbSBzY3JpcHRzLidcclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaW5wdXQgZmlsZSBzaG91bGQgaW5jbHVkZSBhIG5hbWUgYW5kIGEgdHlwZSAoanNvbiBvciBzdmcpLiBJdCBtdXN0IGJlIGNvcnJlY3RseSBmb3JtYXR0ZWQgYXMgYSBKU09OIG9yIFNWRyBmaWxlLidcclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQsIHByb3ZpZGVkIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiBvciBTVkcgZmlsZSwgd2lsbCBvdmVycmlkZSB0aGUgLS1pbmZpbGUgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBjb25zdHJ1Y3RvciB0byB1c2UuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAndGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBiZXR3ZWVuIDAuMSBhbmQgNS4wLidcclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgdGhlbWUgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5pdGlhdGVzIGEgYmF0Y2ggam9iIHdpdGggYSBzdHJpbmcgY29udGFpbmluZyBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIi4nXHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHJlbmRlcmluZyBhIHdlYnBhZ2UuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB3aGV0aGVyIHRoZSBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgaXMgYWxsb3dlZCBkdXJpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA4MDgwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGhlIGRlbGF5IGR1cmF0aW9uIGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0gbGltaXQuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50LidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5LidcclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xyXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxyXG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcclxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxyXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxyXG4vLyAqIEluaXRpYWwgdmFsdWVcclxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2FyZ3MnLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfVxyXG4gIF0sXHJcbiAgaGlnaGNoYXJ0czogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdpbmRpY2F0b3JTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5pbmRpY2F0b3JTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmN1c3RvbVNjcmlwdHMudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZXhwb3J0OiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAndHlwZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb25zdHInLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcclxuICAgICAgbWluOiAwLjEsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgY3VzdG9tTG9naWM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgc2VydmVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2hvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgbG9nZ2luZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2xldmVsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxyXG4gICAgICByb3VuZDogMCxcclxuICAgICAgbWluOiAwLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2ZpbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCB0aGUgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZmlsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZGVzdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBsb2cgZmlsZXMuIEVuYWJsZXMgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHVpOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncm91dGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgb3RoZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnbm9kZUVudicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub2RlRW52LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGFyZFJlc2V0UGFnZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5oYXJkUmVzZXRQYWdlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBkZWJ1ZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmhlYWRsZXNzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2RldnRvb2xzJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGV2dG9vbHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Db25zb2xlJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcubGlzdGVuVG9Db25zb2xlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2R1bXBpbycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmR1bXBpby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzbG93TW8nLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5zbG93TW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVidWdnaW5nUG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRlYnVnZ2luZ1BvcnQudmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqXHJcbiAqIEBmaWxlb3ZlcnZpZXdcclxuICogVGhpcyBmaWxlIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgd2l0aCB0aGUgJ3pvZCdcclxuICogbGlicmFyeS4gVGhlIHBhcnNlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHRoZW4gZXhwb3J0ZWQgdG8gYmUgdXNlZFxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgXCJlbnZzXCIuIFdlIHNob3VsZCBub3QgdXNlIHByb2Nlc3MuZW52IGRpcmVjdGx5XHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxyXG4gKlxyXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxyXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IHNjcmlwdHNOYW1lcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuLy8gaW4gdGhlIENvbmZpZyBvYmplY3RcclxuY29uc3QgdiA9IHtcclxuICAvLyBTcGxpdHMgc3RyaW5nIHZhbHVlIGludG8gZWxlbWVudHMgaW4gYW4gYXJyYXksIHRyaW1zIGV2ZXJ5IGVsZW1lbnQsIGNoZWNrc1xyXG4gIC8vIGlmIGFuIGFycmF5IGlzIGNvcnJlY3QsIGlmIGl0IGlzIGVtcHR5LCBhbmQgaWYgaXQgaXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgYXJyYXk6IChmaWx0ZXJBcnJheSkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlXHJcbiAgICAgICAgICAuc3BsaXQoJywnKVxyXG4gICAgICAgICAgLm1hcCgodmFsdWUpID0+IHZhbHVlLnRyaW0oKSlcclxuICAgICAgICAgIC5maWx0ZXIoKHZhbHVlKSA9PiBmaWx0ZXJBcnJheS5pbmNsdWRlcyh2YWx1ZSkpXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgb25seSB0cnVlLCBmYWxzZSBhbmQgY29ycmVjdGx5IHBhcnNlIHRoZSB2YWx1ZSB0byBib29sZWFuXHJcbiAgLy8gb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSB1bmRlZmluZWRcclxuICBib29sZWFuOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbJ3RydWUnLCAnZmFsc2UnLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgPT09ICd0cnVlJyA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcGFzc2VkIHZhbHVlcyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgZW51bTogKHZhbHVlcykgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWy4uLnZhbHVlcywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIFRyaW1zIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNoZWNrcyBpZiBpdCBpcyBlbXB0eSBvciBjb250YWlucyBzdHJpbmdpZmllZFxyXG4gIC8vIHZhbHVlcyBzdWNoIGFzIGZhbHNlLCB1bmRlZmluZWQsIG51bGwsIE5hTiwgaWYgaXQgZG9lcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBzdHJpbmc6ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJ10uaW5jbHVkZXModmFsdWUpIHx8XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgZm9yYmlkZGVuIHZhbHVlcywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBvc2l0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIHBvc2l0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBwb3NpdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG5vbi1uZWdhdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlXHJcbiAgLy8gd2lsbCBiZSB1bmRlZmluZWRcclxuICBub25OZWdhdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKVxyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IENvbmZpZyA9IHoub2JqZWN0KHtcclxuICAvLyBoaWdoY2hhcnRzXHJcbiAgSElHSENIQVJUU19WRVJTSU9OOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT4gL14obGF0ZXN0fFxcZCsoXFwuXFxkKyl7MCwyfSkkLy50ZXN0KHZhbHVlKSB8fCB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlosIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpIHx8XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpIHx8XHJcbiAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIEhJR0hDSEFSVFNfQ0ROX1VSTC4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggaHR0cDovLyBvciBodHRwczovLywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuY29yZSksXHJcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMubW9kdWxlcyksXHJcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuaW5kaWNhdG9ycyksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdi5ib29sZWFuKCksXHJcbiAgSElHSENIQVJUU19DQUNIRV9QQVRIOiB2LnN0cmluZygpLFxyXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxyXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlclxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHNlcnZlciBzc2xcclxuICBTRVJWRVJfU1NMX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9GT1JDRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfUkVBUEVSX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBsb2dnZXJcclxuICBMT0dHSU5HX0xFVkVMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZSA9PT0gJycgfHxcclxuICAgICAgICAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPD0gNSksXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgTE9HR0lOR19MRVZFTC4gV2Ugb25seSBhY2NlcHQgdmFsdWVzIGZyb20gMCB0byA1IGFzIGxvZ2dpbmcgbGV2ZWxzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG4gIExPR0dJTkdfRklMRTogdi5zdHJpbmcoKSxcclxuICBMT0dHSU5HX0RFU1Q6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHVpXHJcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBVSV9ST1VURTogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gb3RoZXJcclxuICBPVEhFUl9OT0RFX0VOVjogdi5lbnVtKFsnZGV2ZWxvcG1lbnQnLCAncHJvZHVjdGlvbicsICd0ZXN0J10pLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9OT19MT0dPOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19TTE9XX01POiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgREVCVUdfREVCVUdHSU5HX1BPUlQ6IHYucG9zaXRpdmVOdW0oKVxyXG59KTtcclxuXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gQ29uZmlnLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxubGV0IGxvZ2dpbmcgPSB7XHJcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXHJcbiAgdG9Db25zb2xlOiB0cnVlLFxyXG4gIHRvRmlsZTogZmFsc2UsXHJcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxyXG4gIC8vIExvZyBsZXZlbHNcclxuICBsZXZlbHNEZXNjOiBbXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzBdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzFdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ25vdGljZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgLy8gTG9nIGxpc3RlbmVyc1xyXG4gIGxpc3RlbmVyczogW11cclxufTtcclxuXHJcbi8vIEdhdGhlciBpbml0IGxvZ2dpbmcgb3B0aW9uc1xyXG5mb3IgKGNvbnN0IFtrZXksIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZGVmYXVsdENvbmZpZy5sb2dnaW5nKSkge1xyXG4gIGxvZ2dpbmdba2V5XSA9IG9wdGlvbi52YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHMgdGhlXHJcbiAqIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nW119IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuY29uc3QgbG9nVG9GaWxlID0gKHRleHRzLCBwcmVmaXgpID0+IHtcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICAgIWV4aXN0c1N5bmMobG9nZ2luZy5kZXN0KSAmJiBta2RpclN5bmMobG9nZ2luZy5kZXN0KTtcclxuXHJcbiAgICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XHJcbiAgICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICAgIGFwcGVuZEZpbGUoXHJcbiAgICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxyXG4gICAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgICAoZXJyb3IpID0+IHtcclxuICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGU6ICR7ZXJyb3J9YCk7XHJcbiAgICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcclxuICogYGxldmVsYCB3aWxsIGJlIHBhc3NlZCBkaXJlY3RseSB0byBjb25zb2xlLmxvZywgYW5kL29yIHdpbGwgYmUgam9pbmVkXHJcbiAqIGFuZCBhcHBlbmRlZCB0byB0aGUgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nIGxldmVsXHJcbiAqIGFuZCB0aGUgcmVzdCBhcmUgc3RyaW5ncyB0byBidWlsZCBhIG1lc3NhZ2Ugd2l0aC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2cgPSAoLi4uYXJncykgPT4ge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIGFsb25nXHJcbiAqIHdpdGggdGhlIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZ1dpdGhTdGFjayA9IChuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpID0+IHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIElmIHRoZSBjdXN0b21NZXNzYWdlIGV4aXN0cywgd2Ugd2FudCB0byBkaXNwbGF5IHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID1cclxuICAgIGVycm9yLm1lc3NhZ2UgIT09IGVycm9yLnN0YWNrTWVzc2FnZSB8fCBlcnJvci5zdGFja01lc3NhZ2UgPT09IHVuZGVmaW5lZFxyXG4gICAgICA/IGVycm9yLnN0YWNrXHJcbiAgICAgIDogZXJyb3Iuc3RhY2suc3BsaXQoJ1xcbicpLnNsaWNlKDEpLmpvaW4oJ1xcbicpO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3QgdGV4dHMgPSBbbWFpbk1lc3NhZ2UsICdcXG4nLCBzdGFja01lc3NhZ2VdO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICBtYWluTWVzc2FnZVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgJ1xcbicsXHJcbiAgICAgICAgc3RhY2tNZXNzYWdlXHJcbiAgICAgIF0pXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXHJcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlIG9yIDUgPSBiZW5jaG1hcmspXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBuZXcgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xyXG4gIGlmIChuZXdMZXZlbCA+PSAwICYmIG5ld0xldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBuZXdMZXZlbDtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0Rlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgbG9nIGZpbGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcclxuICAvLyBVcGRhdGUgbG9nZ2luZyBvcHRpb25zXHJcbiAgbG9nZ2luZyA9IHtcclxuICAgIC4uLmxvZ2dpbmcsXHJcbiAgICBkZXN0OiBsb2dEZXN0IHx8IGxvZ2dpbmcuZGVzdCxcclxuICAgIGZpbGU6IGxvZ0ZpbGUgfHwgbG9nZ2luZy5maWxlLFxyXG4gICAgdG9GaWxlOiB0cnVlXHJcbiAgfTtcclxuXHJcbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiBsb2coMSwgJ1tsb2dnZXJdIEZpbGUgbG9nZ2luZyBpbml0aWFsaXphdGlvbjogbm8gcGF0aCBzdXBwbGllZC4nKTtcclxuICB9XHJcblxyXG4gIGlmICghbG9nZ2luZy5kZXN0LmVuZHNXaXRoKCcvJykpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCArPSAnLyc7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmcgLSBUaGUgbG9nZ2luZyBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0TG9nZ2luZyA9IChsb2dnaW5nKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsb2dnaW5nICYmIHBhcnNlSW50KGxvZ2dpbmcubGV2ZWwpKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXHJcbiAgaWYgKGxvZ2dpbmcgJiYgbG9nZ2luZy5kZXN0KSB7XHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgbG9nZ2luZy5kZXN0LFxyXG4gICAgICBsb2dnaW5nLmZpbGUgfHwgJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gdG8gdGhlIGxvZ2dpbmcgc3lzdGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBsaXN0ZW5lciBmdW5jdGlvbiB0byBiZSBhZGRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsaXN0ZW4gPSAoZm4pID0+IHtcclxuICBsb2dnaW5nLmxpc3RlbmVycy5wdXNoKGZuKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBUb2dnbGVzIHRoZSBzdGFuZGFyZCBvdXRwdXQgKGNvbnNvbGUpIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCAtIElmIHRydWUsIGVuYWJsZXMgY29uc29sZSBsb2dnaW5nOyBpZiBmYWxzZSxcclxuICogZGlzYWJsZXMgaXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9nZ2xlU1RET3V0ID0gKGVuYWJsZWQpID0+IHtcclxuICBsb2dnaW5nLnRvQ29uc29sZSA9IGVuYWJsZWQ7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBpbml0TG9nZ2luZyxcclxuICBsaXN0ZW4sXHJcbiAgdG9nZ2xlU1RET3V0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4uL2xpYi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuY29uc3QgTUFYX0JBQ0tPRkZfQVRURU1QVFMgPSA2O1xyXG5cclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCB0ZXh0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7UmVnRXhwfSBbcnVsZT0vXFxzXFxzKy9nXSAtIFRoZSByZWd1bGFyIGV4cHJlc3Npb24gcnVsZSB0byBtYXRjaFxyXG4gKiBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY2xlYXJlZCBhbmQgc3RhbmRhcmRpemVkIHRleHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJUZXh0ID0gKHRleHQsIHJ1bGUgPSAvXFxzXFxzKy9nLCByZXBsYWNlciA9ICcgJykgPT5cclxuICB0ZXh0LnJlcGxhY2VBbGwocnVsZSwgcmVwbGFjZXIpLnRyaW0oKTtcclxuXHJcbi8qKlxyXG4gKiBJbXBsZW1lbnRzIGFuIGV4cG9uZW50aWFsIGJhY2tvZmYgc3RyYXRlZ3kgZm9yIHJldHJ5aW5nIGEgZnVuY3Rpb24gdW50aWxcclxuICogYSBjZXJ0YWluIG51bWJlciBvZiBhdHRlbXB0cyBhcmUgcmVhY2hlZC5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuXHJcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uXHJcbiAqIGlmIHN1Y2Nlc3NmdWwuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcclxuICogaXMgcmVhY2hlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHBCYWNrb2ZmID0gYXN5bmMgKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXHJcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xyXG5cclxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVhcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBXYWl0ZWQgJHtkZWxheUluTXN9bXMgdW50aWwgbmV4dCBjYWxsIGZvciB0aGUgcmVzb3VyY2UgaWQ6ICR7YXJnc1swXX0uYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUcnkgYWdhaW5cclxuICAgIHJldHVybiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0LCAuLi5hcmdzKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZml4VHlwZSA9ICh0eXBlLCBvdXRmaWxlKSA9PiB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEZvcm1hdHNcclxuICBjb25zdCBmb3JtYXRzID0gWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ107XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IHJlc291cmNlcyAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC4gQ2FuIGJlIGVpdGhlclxyXG4gKiBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OIG9yIGEgcGF0aCB0byBhIEpTT04gZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBXaGV0aGVyIHRvIGFsbG93IGxvYWRpbmcgcmVzb3VyY2VzIGZyb21cclxuICogZmlsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8dW5kZWZpbmVkfSAtIFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciB1bmRlZmluZWQgaWYgbm8gdmFsaWRcclxuICogcmVzb3VyY2VzIGFyZSBmb3VuZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBoYW5kbGVSZXNvdXJjZXMgPSAocmVzb3VyY2VzID0gZmFsc2UsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZWFkRmlsZVN5bmMocmVzb3VyY2VzLCAndXRmOCcpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIFRyeSB0byBnZXQgSlNPTlxyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn07XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIGFuZCBwYXJzZXMgSlNPTiBkYXRhLiBDaGVja3MgaWYgcHJvdmlkZWQgZGF0YSBpcyBvciBjYW5cclxuICogYmUgYSBjb3JyZWN0IEpTT04uIElmIGEgcHJpbWl0aXZlIGlzIHByb3ZpZGVkLCBpdCBpcyBzdHJpbmdpZmllZCBhbmQgcmV0dXJuZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gZGF0YSAtIFRoZSBKU09OIGRhdGEgdG8gYmUgdmFsaWRhdGVkIGFuZCBwYXJzZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9TdHJpbmcgLSBXaGV0aGVyIHRvIHJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgSlNPTi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgcGFyc2VkIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLFxyXG4gKiBvciBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQ29ycmVjdEpTT04oZGF0YSwgdG9TdHJpbmcpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gaWYgbm90IGFscmVhZHkgYmVmb3JlIHBhcnNpbmdcclxuICAgIGNvbnN0IHBhcnNlZERhdGEgPSBKU09OLnBhcnNlKFxyXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcclxuICAgICk7XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXHJcbiAgICBpZiAodHlwZW9mIHBhcnNlZERhdGEgIT09ICdzdHJpbmcnICYmIHRvU3RyaW5nKSB7XHJcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXJzZWREYXRhKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gYSBKU09OXHJcbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcclxuICB9IGNhdGNoIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3QgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiYgaXRlbSAhPT0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0RW1wdHkgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gIGl0ZW0gIT09IG51bGwgJiZcclxuICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDA7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2VcclxuICogb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgPSAoaXRlbSkgPT4ge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgdGhlIGdpdmVuIG9iamVjdCBvciBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IG9iaiAtIFRoZSBvYmplY3Qgb3IgYXJyYXkgdG8gYmUgZGVlcGx5IGNvcGllZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxBcnJheX0gLSBUaGUgZGVlcCBjb3B5IG9mIHRoZSBwcm92aWRlZCBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVlcENvcHkgPSAob2JqKSA9PiB7XHJcbiAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iajtcclxuICB9XHJcblxyXG4gIGNvbnN0IGNvcHkgPSBBcnJheS5pc0FycmF5KG9iaikgPyBbXSA6IHt9O1xyXG5cclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSB7XHJcbiAgICAgIGNvcHlba2V5XSA9IGRlZXBDb3B5KG9ialtrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBjb3B5O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZyB3aXRoIHRoZVxyXG4gKiBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBvcHRpb25zU3RyaW5naWZ5ID0gKG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zKSA9PiB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChuYW1lLCB2YWx1ZSkgPT4ge1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcblxyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChcclxuICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCcpKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JylcclxuICAgICAgKSB7XHJcbiAgICAgICAgdmFsdWUgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJ1xyXG4gICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICA6IHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG5vTG9nbyAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHZlcnNpb24gaW5mb3JtYXRpb24gd2l0aG91dFxyXG4gKiB0aGUgbG9nby5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwcmludExvZ28gPSAobm9Mb2dvKSA9PiB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cclxuICBjb25zdCBwYWNrYWdlVmVyc2lvbiA9IEpTT04ucGFyc2UoXHJcbiAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSlcclxuICApLnZlcnNpb247XHJcblxyXG4gIC8vIFByaW50IHRleHQgb25seVxyXG4gIGlmIChub0xvZ28pIHtcclxuICAgIGNvbnNvbGUubG9nKGBTdGFydGluZyBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdiR7cGFja2FnZVZlcnNpb259Li4uYCk7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBQcmludCB0aGUgbG9nb1xyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvbXNnL3N0YXJ0dXAubXNnJykudG9TdHJpbmcoKS5ib2xkLnllbGxvdyxcclxuICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgYWJzb2x1dGVQcm9wcyxcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZEFyZ3MsXHJcbiAgcHJvbXB0c0NvbmZpZ1xyXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGRlZXBDb3B5LCBpc09iamVjdCwgcHJpbnRVc2FnZSwgdG9Cb29sZWFuIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRPcHRpb25zID0gKCkgPT4gZ2VuZXJhbE9wdGlvbnM7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHNldHMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIHNlcnZlciBpbnN0YWNlLCBrZWVwaW5nXHJcbiAqIHRoZSBwcmluY2lwbGUgb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eS4gSXQgYWNjZXB0cyBvcHRpb25hbCB1c2VyT3B0aW9uc1xyXG4gKiBhbmQgYXJncyBmcm9tIHRoZSBDTEkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1c2VyT3B0aW9ucyAtIFVzZXItcHJvdmlkZWQgb3B0aW9ucyBmb3IgY3VzdG9taXphdGlvbi5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxyXG4gKiAoQ0xJIHVzYWdlKS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRPcHRpb25zID0gKHVzZXJPcHRpb25zLCBhcmdzKSA9PiB7XHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIEdldCB0aGUgYWRkaXRpb25hbCBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGZpbGVcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcclxuICB1cGRhdGVEZWZhdWx0Q29uZmlnKGRlZmF1bHRDb25maWcsIGdlbmVyYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXHJcbiAgZ2VuZXJhbE9wdGlvbnMgPSBpbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcclxuICBpZiAodXNlck9wdGlvbnMpIHtcclxuICAgIC8vIE1lcmdlIHVzZXIgb3B0aW9uc1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICB1c2VyT3B0aW9ucyxcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBwYWlyQXJndW1lbnRWYWx1ZShnZW5lcmFsT3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gZmluYWwgZ2VuZXJhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFsbG93cyBtYW51YWwgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBzcGVjaWZpZWQgcHJvbXB0cyBhbmQgc2F2ZXNcclxuICogdGhlIGNvbmZpZ3VyYXRpb24gdG8gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBvbmNlIHRoZSBtYW51YWxcclxuICogY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZWQgYW5kIHNhdmVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hbnVhbENvbmZpZyA9IGFzeW5jIChjb25maWdGaWxlTmFtZSkgPT4ge1xyXG4gIC8vIFByZXBhcmUgYSBjb25maWcgb2JqZWN0XHJcbiAgbGV0IGNvbmZpZ0ZpbGUgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgY29uZmlnIGZpbGUgZXhpc3RzXHJcbiAgaWYgKGV4aXN0c1N5bmMoY29uZmlnRmlsZU5hbWUpKSB7XHJcbiAgICBjb25maWdGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnRmlsZU5hbWUsICd1dGY4JykpO1xyXG4gIH1cclxuXHJcbiAgLy8gUXVlc3Rpb24gYWJvdXQgYSBjb25maWd1cmF0aW9uIGNhdGVnb3J5XHJcbiAgY29uc3Qgb25TdWJtaXQgPSBhc3luYyAocCwgY2F0ZWdvcmllcykgPT4ge1xyXG4gICAgbGV0IHF1ZXN0aW9uc0NvdW50ZXIgPSAwO1xyXG4gICAgbGV0IGFsbFF1ZXN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gdGhlIG1hbnVhbENvbmZpZyBvYmplY3RcclxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBjYXRlZ29yaWVzKSB7XHJcbiAgICAgIC8vIE1hcmsgZWFjaCBvcHRpb24gd2l0aCBhIHNlY3Rpb25cclxuICAgICAgcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXSA9IHByb21wdHNDb25maWdbc2VjdGlvbl0ubWFwKChvcHRpb24pID0+ICh7XHJcbiAgICAgICAgLi4ub3B0aW9uLFxyXG4gICAgICAgIHNlY3Rpb25cclxuICAgICAgfSkpO1xyXG5cclxuICAgICAgLy8gQ29sbGVjdCB0aGUgcXVlc3Rpb25zXHJcbiAgICAgIGFsbFF1ZXN0aW9ucyA9IFsuLi5hbGxRdWVzdGlvbnMsIC4uLnByb21wdHNDb25maWdbc2VjdGlvbl1dO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IHByb21wdHMoYWxsUXVlc3Rpb25zLCB7XHJcbiAgICAgIG9uU3VibWl0OiBhc3luYyAocHJvbXB0LCBhbnN3ZXIpID0+IHtcclxuICAgICAgICAvLyBHZXQgdGhlIGRlZmF1bHQgbW9kdWxlIHNjcmlwdHNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVTY3JpcHRzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcblxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgdXBkYXRlRGVmYXVsdENvbmZpZyhlbnRyeSwgY3VzdG9tVmFsdWUsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYSBjdXN0b20gSlNPTiBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY3VzdG9tVmFsdWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gY3VzdG9tVmFsdWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhbiBlbnYgdmFyaWFibGUgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZzW2VudHJ5LmVudkxpbmtdICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGVudnNbZW50cnkuZW52TGlua107XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkIGl0ZW1zLCBzZXR0aW5nIHZhbHVlcyBmcm9tXHJcbiAqIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbXMgLSBDb25maWd1cmF0aW9uIGl0ZW1zIHRvIGJlIHVzZWQgZm9yIGluaXRpYWxpemluZ1xyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGluaXRPcHRpb25zKGl0ZW1zKSB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhpdGVtcykpIHtcclxuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcclxuICAgICAgPyBpdGVtLnZhbHVlXHJcbiAgICAgIDogaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgfVxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUGFpcnMgYXJndW1lbnQgdmFsdWVzIHdpdGggY29ycmVzcG9uZGluZyBvcHRpb25zIGluIHRoZSBjb25maWd1cmF0aW9uLFxyXG4gKiB1cGRhdGluZyB0aGUgb3B0aW9ucyBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCB0byBiZSB1cGRhdGVkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBjb250YWluaW5nIHZhbHVlcyBmb3Igc3BlY2lmaWNcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGRlZmF1bHRDb25maWcgLSBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByZWZlcmVuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBwYWlyQXJndW1lbnRWYWx1ZShvcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKSB7XHJcbiAgbGV0IHNob3dVc2FnZSA9IGZhbHNlO1xyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gYXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkQXJnc1tvcHRpb25dLnNwbGl0KCcuJylcclxuICAgICAgOiBbXTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNvcnJlY3QgdHlwZSBmb3IgQ0xJIGFyZ3Mgd2hpY2ggYXJlIHBhc3NlZCBhcyBzdHJpbmdzXHJcbiAgICBsZXQgYXJndW1lbnRUeXBlO1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgYXJndW1lbnRUeXBlID0gb2JqW3Byb3BdLnR5cGU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIC8vIEZpbmRzIGFuIG9wdGlvbiBhbmQgc2V0IGEgY29ycmVzcG9uZGluZyB2YWx1ZVxyXG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgICAgaWYgKGFyZ3NbKytpXSkge1xyXG4gICAgICAgICAgICBpZiAoYXJndW1lbnRUeXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSB0b0Jvb2xlYW4oYXJnc1tpXSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlID09PSAnbnVtYmVyJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9ICthcmdzW2ldO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZS5pbmRleE9mKCddJykgPj0gMCkge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV0uc3BsaXQoJywnKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlICcke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHNob3dVc2FnZSA9IHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBvcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIERpc3BsYXkgdGhlIHVzYWdlIGZvciB0aGUgcmVmZXJlbmNlIGlmIG5lZWRlZFxyXG4gIGlmIChzaG93VXNhZ2UpIHtcclxuICAgIHByaW50VXNhZ2UoZGVmYXVsdENvbmZpZyk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IHVwZGF0ZXMgcHJvcGVydGllcyBpbiBhbiBvYmplY3QgYmFzZWQgb24gbmVzdGVkIG5hbWVzIGFuZCBhc3NpZ25zXHJcbiAqIHRoZSBmaW5hbCB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFRvVXBkYXRlIC0gVGhlIG9iamVjdCB0byBiZSB1cGRhdGVkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBuZXN0ZWROYW1lcyAtIEFycmF5IG9mIG5lc3RlZCBwcm9wZXJ0eSBuYW1lcy5cclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIGZpbmFsIHZhbHVlIHRvIGJlIGFzc2lnbmVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9iamVjdCB3aXRoIGFzc2lnbmVkIHZhbHVlcy5cclxuICovXHJcbmZ1bmN0aW9uIHJlY3Vyc2l2ZVByb3BzKG9iamVjdFRvVXBkYXRlLCBuZXN0ZWROYW1lcywgdmFsdWUpIHtcclxuICB3aGlsZSAobmVzdGVkTmFtZXMubGVuZ3RoID4gMSkge1xyXG4gICAgY29uc3QgcHJvcE5hbWUgPSBuZXN0ZWROYW1lcy5zaGlmdCgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHByb3BlcnR5IGluIG9iamVjdCBpZiBpdCBkb2Vzbid0IGV4aXN0XHJcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3RUb1VwZGF0ZSwgcHJvcE5hbWUpKSB7XHJcbiAgICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHt9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENhbGwgZnVuY3Rpb24gYWdhaW4gaWYgdGhlcmUgc3RpbGwgbmFtZXMgdG8gZ29cclxuICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0pLFxyXG4gICAgICBuZXN0ZWROYW1lcyxcclxuICAgICAgdmFsdWVcclxuICAgICk7XHJcblxyXG4gICAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG4gIH1cclxuXHJcbiAgLy8gQXNzaWduIHRoZSBmaW5hbCB2YWx1ZVxyXG4gIG9iamVjdFRvVXBkYXRlW25lc3RlZE5hbWVzWzBdXSA9IHZhbHVlO1xyXG4gIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWVyZ2VDb25maWdPcHRpb25zLFxyXG4gIGluaXRFeHBvcnRTZXR0aW5nc1xyXG59O1xyXG4iLCIvKipcclxuICogVGhpcyBtb2R1bGUgZXhwb3J0cyB0d28gZnVuY3Rpb25zOiBmZXRjaCAoZm9yIEdFVCByZXF1ZXN0cykgYW5kIHBvc3QgKGZvciBQT1NUIHJlcXVlc3RzKS5cclxuICovXHJcblxyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuY29uc3QgZ2V0UHJvdG9jb2wgPSAodXJsKSA9PiAodXJsLnN0YXJ0c1dpdGgoJ2h0dHBzJykgPyBodHRwcyA6IGh0dHApO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0XHJcbiAqIHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuXHJcbiAgICBwcm90b2NvbFxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgZGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIWRhdGEpIHtcclxuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XHJcbiAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gc2VuZCB0aGUgUE9TVCByZXF1ZXN0IHRvLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gYm9keSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0XHJcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXHJcbiAqIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXEgPSBwcm90b2NvbFxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgcmVzLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3QuXHJcbiAgICByZXEud3JpdGUoZGF0YSk7XHJcbiAgICByZXEuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZldGNoO1xyXG5leHBvcnQgeyBmZXRjaCwgcG9zdCB9O1xyXG4iLCJjbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlKSB7XHJcbiAgICBzdXBlcigpO1xyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuICB9XHJcblxyXG4gIHNldEVycm9yKGVycm9yKSB7XHJcbiAgICB0aGlzLmVycm9yID0gZXJyb3I7XHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gVGhlIGNhY2hlIG1hbmFnZXIgbWFuYWdlcyB0aGUgSGlnaGNoYXJ0cyBsaWJyYXJ5IGFuZCBpdHMgZGVwZW5kZW5jaWVzLlxyXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXHJcbi8vIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmljZVxyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0VmVyc2lvbiA9IChjYWNoZSkgPT4ge1xyXG4gIHJldHVybiBjYWNoZS5zb3VyY2VzXHJcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0TW9kdWxlTmFtZSA9IChzY3JpcHRQYXRoKSA9PiB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzLXJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIG1hcHBlZCBuYW1lcyBvZlxyXG4gKiBmZXRjaGVkIEhpZ2hjaGFydHMgbW9kdWxlcyB0byB1c2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlIHdyaXRpbmdcclxuICogdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxyXG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlXHJcbiAqIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZldGNoQW5kUHJvY2Vzc1NjcmlwdCA9IGFzeW5jIChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikgPT4ge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcblxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvcmVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tU2NyaXB0cyAtIEFycmF5IG9mIGN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2hcclxuICogKGZ1bGwgVVJMcykuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm94eU9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvclxyXG4gKiBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZldGNoU2NyaXB0cyA9IGFzeW5jIChcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikgPT4ge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBwcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBwcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcclxuICAgICAgICBlcnJvclxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXHJcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBwcm94eUFnZW50XHJcbiAgICA/IHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBlbnZzLlNFUlZFUl9QUk9YWV9USU1FT1VUXHJcbiAgICAgIH1cclxuICAgIDoge307XHJcblxyXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXHJcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucylcclxuICAgIClcclxuICBdO1xyXG5cclxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xyXG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XHJcbn07XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBzb3VyY2VQYXRoXHJcbikgPT4ge1xyXG4gIGNvbnN0IHZlcnNpb24gPSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9IHZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICF2ZXJzaW9uID8gJycgOiBgJHt2ZXJzaW9ufS9gO1xyXG4gIGNvbnN0IGNkblVSTCA9IGhpZ2hjaGFydHNPcHRpb25zLmNkblVSTCB8fCBjYWNoZS5jZG5VUkw7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuICB0cnkge1xyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IGZldGNoU2NyaXB0cyhcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufSR7Y31gKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGAke2NkblVSTH1tYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICksXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoXHJcbiAgICAgICAgICAoaSkgPT4gYCR7Y2RuVVJMfXN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xyXG4gKiB0aGUgY2FjaGUgZm9yIHRoZSBuZXcgdmVyc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5ld1ZlcnNpb24gLSBUaGUgbmV3IEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSBhcHBsaWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwob2JqZWN0fGJvb2xlYW4pPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZFxyXG4gKiBjb25maWd1cmF0aW9uIHdpdGggdGhlIG5ldyB2ZXJzaW9uLCBvciBmYWxzZSBpZiBubyBhcHBsaWVkIGNvbmZpZ3VyYXRpb25cclxuICogZXhpc3RzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVwZGF0ZVZlcnNpb24gPSBhc3luYyAobmV3VmVyc2lvbikgPT4ge1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcbiAgaWYgKG9wdGlvbnM/LmhpZ2hjaGFydHMpIHtcclxuICAgIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcclxuICB9XHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXHJcbiAqIGFuZCB1cGRhdGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgaGlnaGNoYXJ0cywgc2VydmVyIH0gPSBvcHRpb25zO1xyXG4gIGNvbnN0IGNhY2hlUGF0aCA9IGpvaW4oX19kaXJuYW1lLCBoaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoKTtcclxuXHJcbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiBtYW5pZmVzdC5qc29uIGRvZXMgbm90IGV4aXN0XHJcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcclxuICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHM7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBoaWdoY2hhcnRzIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGhpZ2hjaGFydHMudmVyc2lvbikge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXMpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gVGhlIGNhY2hlIGFuZCB0aGUgcmVxdWVzdGVkIG1vZHVsZXMgZG8gbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHMsIGZldGNoZWRNb2R1bGVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZVBhdGggPSAoKSA9PlxyXG4gIGpvaW4oX19kaXJuYW1lLCBnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoLFxyXG4gIHVwZGF0ZVZlcnNpb24sXHJcbiAgZ2V0Q2FjaGU6ICgpID0+IGNhY2hlLFxyXG4gIGhpZ2hjaGFydHM6ICgpID0+IGNhY2hlLnNvdXJjZXMsXHJcbiAgdmVyc2lvbjogKCkgPT4gY2FjaGUuaGNWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKiogQ3JlYXRlIHRoZSBhY3R1YWwgY2hhcnQgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRyaWdnZXJFeHBvcnQoY2hhcnRPcHRpb25zLCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSB7XHJcbiAgLy8gRGlzcGxheSBlcnJvcnMgZmxhZyB0YWtlbiBmcm9tIGNoYXJ0IG9wdGlvbnMgbmFkIGRlYnVnZ2VyIG1vZHVsZVxyXG4gIHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGRpc3BsYXlFcnJvcnM7XHJcblxyXG4gIC8vIEdldCByZXF1aXJlZCBmdW5jdGlvbnNcclxuICBjb25zdCB7IGdldE9wdGlvbnMsIG1lcmdlLCBzZXRPcHRpb25zLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGEgcG90ZW50aWFsIHNldE9wdGlvbnMgdXNhZ2VzIGluIG9yZGVyIHRvXHJcbiAgLy8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBUcmlnZ2VyIGN1c3RvbSBjb2RlXHJcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkoKTtcclxuICB9XHJcblxyXG4gIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgY29uc3QgY2hhcnQgPSB7XHJcbiAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XHJcbiAgaWYgKG9wdGlvbnMuZXhwb3J0LnN0ckluaikge1xyXG4gICAgY2hhcnQuaGVpZ2h0ID0gY2hhcnRPcHRpb25zLmNoYXJ0LmhlaWdodDtcclxuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xyXG4gIH1cclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/P1xyXG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIHNldE9wdGlvbnMoSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zKSk7XHJcblxyXG4gIEhpZ2hjaGFydHNbb3B0aW9ucy5leHBvcnQuY29uc3RyIHx8ICdjaGFydCddKFxyXG4gICAgJ2NvbnRhaW5lcicsXHJcbiAgICBmaW5hbE9wdGlvbnMsXHJcbiAgICBmaW5hbENhbGxiYWNrXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgc2V0T3B0aW9ucyB3YXMgdXNlZCBpbiB0aGUgY3VzdG9tQ29kZSlcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBmcyBmcm9tICdmcyc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuY29uc3QgdGVtcGxhdGUgPSBmcy5yZWFkRmlsZVN5bmMoXHJcbiAgX19kaXJuYW1lICsgJy8uLi90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsXHJcbiAgJ3V0ZjgnXHJcbik7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpLmRlYnVnO1xyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogJ3NoZWxsJyxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWcpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgICdbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHRoZSBjb250ZW50IG9mIHRoZSBwYWdlLidcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdHJpZ2dlckV4cG9ydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZ1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzb3VyY2UuZGlzcG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFVzZSByZXNvdXJjZXNcclxuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gICAgaWYgKHJlc291cmNlcykge1xyXG4gICAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUkFTVEVSSVpBVElPTlxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKHBhZ2UsIHZpZXdwb3J0SGVpZ2h0LCB2aWV3cG9ydFdpZHRoLCAnYmFzZTY0Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY2xvc2UgYXMgYnJvd3NlckNsb3NlLFxyXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxyXG4gIG5ld1BhZ2UgYXMgYnJvd3Nlck5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gICAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHRoZSBwYWdlZXJyb3IgbGlzdGVuZXJcclxuICAgIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxyXG4gICAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCB7IG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZSh3b3JrZXJIYW5kbGUucGFnZSwgb3RoZXIuaGFyZFJlc2V0UGFnZSk7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXHJcbiAgICovXHJcbiAgZGVzdHJveTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgbG9nKDMsIGBbcG9vbF0gRGVzdHJveWluZyBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gV2UgZG9uJ3QgcmVhbGx5IG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgYXdhaXQgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIoY29uZmlnLnB1cHBldGVlckFyZ3MpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxyXG4gICk7XHJcblxyXG4gIGlmIChwb29sKSB7XHJcbiAgICByZXR1cm4gbG9nKFxyXG4gICAgICA0LFxyXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xyXG4gICAgcG9vbENvbmZpZy5taW5Xb3JrZXJzID0gcG9vbENvbmZpZy5tYXhXb3JrZXJzO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXHJcbiAgICAgIC4uLmZhY3RvcnksXHJcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcclxuICAgICAgbWF4OiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogS2lsbHMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGJyb3dzZXJDbG9zZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxyXG4gICAgICAgICAgOiAnJykgK1xyXG4gICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKiovXHJcblxyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXHJcbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXHJcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XHJcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRJbnRlcnZhbCxcclxuICBjbGVhckFsbEludGVydmFsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgIHJlcy5zZW5kKHtcclxuICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICB1cHRpbWU6XHJcbiAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXHJcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXHJcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxyXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXHJcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XHJcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICpcclxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLnBvc3QoXHJcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXHJcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInJlY3Vyc2l2ZVByb3BzIiwib2JqZWN0VG9VcGRhdGUiLCJuZXN0ZWROYW1lcyIsInNoaWZ0IiwiYXNzaWduIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsImNhY2hlJDEiLCJuZXdWZXJzaW9uIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsInRyaWdnZXJFeHBvcnQiLCJjaGFydE9wdGlvbnMiLCJkaXNwbGF5RXJyb3JzIiwiX2Rpc3BsYXlFcnJvcnMiLCJtZXJnZSIsInNldE9wdGlvbnMiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsIkZ1bmN0aW9uIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwicHJvcCIsInRlbXBsYXRlIiwiZnMiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJ3YWl0VW50aWwiLCJldmFsdWF0ZSIsImJvZHkiLCJpbm5lckhUTUwiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCIkZXZhbCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwiZXJyb3JNZXNzYWdlIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImV2ZW50SWQiLCJpbml0aWFsUmVzb3VyY2VzIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwiY29ubmVjdGVkIiwiYnJvd3NlckNsb3NlIiwicG9zdFdvcmsiLCJnZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwicGF5bG9hZCIsInJlcXVlc3RJZCIsIndvcmtTdGFydCIsImV4cG9ydENvdW50ZXIiLCJyZXN1bHQiLCJleHBvcnRUaW1lIiwiZ2V0UG9vbEluZm9KU09OIiwibnVtRnJlZSIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJwZW5kaW5nIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJpbnB1dCIsIkpTRE9NIiwiRE9NUHVyaWZ5Iiwic2FuaXRpemUiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsInBhcmFtcyIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiNnRCQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsV0FFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwrQkFDQSx1QkFDQSw2R0FDQSx5QkFDQSxvQ0FDQSxvQkFDQSwwQkFDQSw4Q0FDQSwyQkFDQSwwQkFDQSw2QkFDQSxtQ0FDQSx3Q0FDQSxtQ0FDQSwyQkFDQSxrQ0FDQSx1QkFDQSxpQkFDQSx5QkFDQSw4QkFDQSxvQkFDQSwyQkFDQSxlQUNBLDZCQUNBLGlCQUNBLGFBQ0EsZUFDQSxzQkFDQSxjQUNBLHlCQUNBLG9CQUNBLHVCQUVGQyxLQUFNLFdBQ05DLFlBQWEsMENBR2pCQyxXQUFZLENBQ1ZDLFFBQVMsQ0FDUEosTUFBTyxTQUNQQyxLQUFNLFNBQ05J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 diff --git a/dist/index.esm.js b/dist/index.esm.js index c3d93740..dc74d4cc 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as m from"url";import{fileURLToPath as g}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"node:path";import E from"puppeteer";import{randomBytes as T}from"node:crypto";import{JSDOM as S}from"jsdom";import x from"dompurify";import R from"cors";import L from"express";import _ from"multer";import k from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","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","flowmap"],indicators:["indicators-all"]},I={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!1,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:250,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},C={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:I.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:I.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:I.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:I.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:I.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:I.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:I.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${I.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${I.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:I.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:I.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:I.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:I.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:I.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:I.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:I.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:I.server.host.value},{type:"number",name:"port",message:"Server port",initial:I.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:I.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:I.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:I.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:I.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:I.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:I.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:I.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:I.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:I.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:I.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:I.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:I.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:I.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:I.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:I.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:I.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:I.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:I.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:I.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:I.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:I.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:I.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:I.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:I.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:I.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:I.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:I.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:I.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:I.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:I.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:I.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:I.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:I.other.noLogo.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:I.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:I.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:I.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:I.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:I.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:I.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:I.debug.debuggingPort.value}]},A=["options","globalOptions","themeOptions","resources","payload"],N={},P=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?P(o,`${t}.${r}`):(N[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(N[o.legacyName]=`${t}.${r}`.substring(1)))}}))};P(I),u.config();const $=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),H=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),U=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),G=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),D=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),j=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),M=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:$(O.core),HIGHCHARTS_MODULE_SCRIPTS:$(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:$(O.indicators),HIGHCHARTS_FORCE_FETCH:H(),HIGHCHARTS_CACHE_PATH:G(),HIGHCHARTS_ADMIN_TOKEN:G(),EXPORT_TYPE:U(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:U(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:D(),EXPORT_DEFAULT_WIDTH:D(),EXPORT_DEFAULT_SCALE:D(),EXPORT_RASTERIZATION_TIMEOUT:j(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:H(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:H(),SERVER_ENABLE:H(),SERVER_HOST:G(),SERVER_PORT:D(),SERVER_BENCHMARKING:H(),SERVER_PROXY_HOST:G(),SERVER_PROXY_PORT:D(),SERVER_PROXY_TIMEOUT:j(),SERVER_RATE_LIMITING_ENABLE:H(),SERVER_RATE_LIMITING_MAX_REQUESTS:j(),SERVER_RATE_LIMITING_WINDOW:j(),SERVER_RATE_LIMITING_DELAY:j(),SERVER_RATE_LIMITING_TRUST_PROXY:H(),SERVER_RATE_LIMITING_SKIP_KEY:G(),SERVER_RATE_LIMITING_SKIP_TOKEN:G(),SERVER_SSL_ENABLE:H(),SERVER_SSL_FORCE:H(),SERVER_SSL_PORT:D(),SERVER_SSL_CERT_PATH:G(),POOL_MIN_WORKERS:j(),POOL_MAX_WORKERS:j(),POOL_WORK_LIMIT:D(),POOL_ACQUIRE_TIMEOUT:j(),POOL_CREATE_TIMEOUT:j(),POOL_DESTROY_TIMEOUT:j(),POOL_IDLE_TIMEOUT:j(),POOL_CREATE_RETRY_INTERVAL:j(),POOL_REAPER_INTERVAL:j(),POOL_BENCHMARKING:H(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:G(),LOGGING_DEST:G(),UI_ENABLE:H(),UI_ROUTE:G(),OTHER_NODE_ENV:U(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:H(),OTHER_NO_LOGO:H(),DEBUG_ENABLE:H(),DEBUG_HEADLESS:H(),DEBUG_DEVTOOLS:H(),DEBUG_LISTEN_TO_CONSOLE:H(),DEBUG_DUMPIO:H(),DEBUG_SLOW_MO:j(),DEBUG_DEBUGGING_PORT:D()}).partial().parse(process.env),F=["red","yellow","blue","gray","green"];let V={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:F[0]},{title:"warning",color:F[1]},{title:"notice",color:F[2]},{title:"verbose",color:F[3]},{title:"benchmark",color:F[4]}],listeners:[]};for(const[e,t]of Object.entries(I.logging))V[e]=t.value;const W=(e,i)=>{V.toFile&&(V.pathCreated||(!t(V.dest)&&r(V.dest),V.pathCreated=!0),o(`${V.dest}${V.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),V.toFile=!1)})))},q=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=V;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;V.listeners.forEach((e=>{e(s,r.join(" "))})),V.toConsole&&console.log.apply(void 0,[s.toString()[V.levelsDesc[t-1].color]].concat(r)),W(r,s)},B=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=V;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];V.toConsole&&console.log.apply(void 0,[n.toString()[V.levelsDesc[e-1].color]].concat([o[F[e-1]],"\n",a])),V.listeners.forEach((e=>{e(n,l.join(" "))})),W(l,n)},X=e=>{e>=0&&e<=V.levelsDesc.length&&(V.level=e)},K=(e,t)=>{if(V={...V,dest:e||V.dest,file:t||V.file,toFile:!0},0===V.dest.length)return q(1,"[logger] File logging initialization: no path supplied.");V.dest.endsWith("/")||(V.dest+="/")},J=g(new URL("../.",import.meta.url)),z=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},Y=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=Q(i(e,"utf8"))}catch(e){return B(2,e,"[cli] No resources found.")}else o=Q(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):q(3,"[cli] No resources found.")};function Q(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Z=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Z(e[r]));return t},ee=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function te(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(I).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(I[t]))})),console.log("\n")}const re=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,oe=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&oe(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ie=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let se={};const ne=()=>se,ae=(e,t,r=[])=>{const o=Z(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:ae(o[e],s,r);var i;return o};function le(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?le(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in M&&void 0!==M[i.envLink]&&(i.value=M[i.envLink]))}))}function ce(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ce(o);return t}function pe(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=pe(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function he(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ue extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const de={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},me=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ge=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),q(4,`[cache] Fetching script - ${e}.js`);const i=await he(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ue(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return q(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},fe=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||de.cdnURL;q(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return de.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new ue("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:M.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>ge(`${e}`,l,i,!0))),...t.map((e=>ge(`${e}`,l,i))),...r.map((e=>ge(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),de.hcVersion=me(de),n(r,de.sources),a}catch(e){throw new ue("[cache] Unable to update the local Highcharts cache.").setError(e)}},ve=async e=>{const{highcharts:o,server:s}=e,a=l(J,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)q(3,"[cache] Fetching and caching Highcharts dependencies."),c=await fe(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(q(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(q(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return q(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await fe(o,s.proxy,h):(q(3,"[cache] Dependency cache is up to date, proceeding."),de.sources=i(h,"utf8"),c=t.modules,de.hcVersion=me(de))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};de.activeManifest=r,q(3,"[cache] Writing a new manifest.");try{n(l(J,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new ue("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},ye=()=>l(J,ne().highcharts.cachePath);var be=async e=>{const t=ne();t?.highcharts&&(t.highcharts.version=e),await ve(t)},we=()=>de,Ee=()=>de.hcVersion;const Te=T(64).toString("base64url"),Se=w.join("tmp",`puppeteer-${Te}`),xe=[`--user-data-dir=${w.join(Se,"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"],Re=m.fileURLToPath(new URL(".",import.meta.url)),Le=e.readFileSync(Re+"/../templates/template.html","utf8");let _e;const ke=async e=>{await e.setContent(Le),await e.addScriptTag({path:`${ye()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},Oe=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ke(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){B(2,e,"[browser] Could not clear the content of the page.")}},Ie=async()=>{if(!_e)return!1;const e=await _e.newPage();return await e.setCacheEnabled(!1),await ke(e),e};const Ce=m.fileURLToPath(new URL(".",import.meta.url)),Ae=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ne=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{q(4,"[export] Determining export path.");const n=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=n?.options?.chart?.displayErrors&&we().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(q(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else q(4,"[export] Treating as config."),n.strInj?await Ae(e,{chart:{height:n.height,width:n.width}},r):(t.chart.height=n.height,t.chart.width=n.width,await Ae(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&o.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");o.push(await e.addScriptTag(r?{content:i(t,"utf8")}:{url:t}))}catch(e){B(2,e,`[export] The JS file ${t} cannot be loaded.`)}if(p.css){let t=p.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")?o.push(await e.addStyleTag({url:i})):r.customLogic.allowFileResources&&o.push(await e.addStyleTag({path:a.join(Ce,i)})));o.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const h=c?await e.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||n.height),d=Math.ceil(h?.chartWidth||n.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)});const m=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(m,parseFloat(n.scale));const{height:g,width:f,x:v,y:y}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let b;if(c||await e.setViewport({width:Math.round(f),height:Math.round(g),deviceScaleFactor:parseFloat(n.scale)}),"svg"===n.type)b=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))b=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ue("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:v,y:y},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new ue(`[export] Unsupported output format ${n.type}.`);b=await((e,t,r,o)=>e.pdf({height:t+1,width:r,encoding:o}))(e,u,d,"base64")}return await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await s(e),b}catch(t){return await s(e),t}};const Pe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let $e,He={},Ue=!1;const Ge={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Ie(),!e||e.isClosed())throw new ue("The page is invalid or closed.");q(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ue("Error encountered when creating a new page.").setError(e)}const{debug:o}=ne();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(He.workLimit/2))}},validate:async e=>He.workLimit&&++e.workCount>He.workLimit?(q(3,`[pool] Worker failed validation: exceeded work limit (limit is ${He.workLimit}).`),!1):(await Oe(e.page,!0),!0),destroy:e=>{q(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},De=async e=>{if(He=e&&e.pool?{...e.pool}:{},$e=e.puppeteerArgs,await(async e=>{const t=[...xe,...e||[]],{enable:r,...o}=ne().debug,i={headless:"new",userDataDir:"./tmp/",args:t,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,...r&&o};if(!_e){let e=0;const t=async()=>{try{q(3,`[browser] Attempting to get a browser instance (try ${++e}).`),_e=await E.launch(i)}catch(r){if(B(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;q(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t()}catch(e){throw new ue("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!_e)throw new ue("[browser] Cannot find a browser to open.")}return _e})($e),q(3,`[pool] Initializing pool with workers: min ${He.minWorkers}, max ${He.maxWorkers}.`),Ue)return q(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(He.minWorkers)>parseInt(He.maxWorkers)&&(He.minWorkers=He.maxWorkers);try{Ue=new y({...Ge,min:parseInt(He.minWorkers),max:parseInt(He.maxWorkers),acquireTimeoutMillis:He.acquireTimeout,createTimeoutMillis:He.createTimeout,destroyTimeoutMillis:He.destroyTimeout,idleTimeoutMillis:He.idleTimeout,createRetryIntervalMillis:He.createRetryInterval,reapIntervalMillis:He.reaperInterval,propagateCreateError:!1}),Ue.on("release",(async e=>{await Oe(e.page,!1),q(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ue.on("destroySuccess",((e,t)=>{q(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ue.release(e)})),q(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ue("[pool] Could not create the pool of workers.").setError(e)}};async function je(){if(q(3,"[pool] Killing pool with all workers and closing browser."),Ue){for(const e of Ue.used)Ue.release(e.resource);Ue.destroyed||(await Ue.destroy(),q(4,"[browser] Destroyed the pool of resources."))}await(async()=>{_e?.isConnected()&&await _e.close(),q(4,"[browser] Closed the browser.")})()}const Me=async(e,t)=>{let r;try{if(q(4,"[pool] Work received, starting to process."),++Pe.exportAttempts,He.benchmarking&&Fe(),!Ue)throw new ue("Work received, but pool has not been started.");try{q(4,"[pool] Acquiring a worker handle.");const e=ie();r=await Ue.acquire().promise,t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new ue("Error encountered when acquiring an available entry.").setError(e)}if(q(4,"[pool] Acquired a worker handle."),!r.page)throw new ue("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();q(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const i=ie(),s=await Ne(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await Ie()),new ue("Error encountered during export.").setError(s);t.server.benchmarking&&q(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${i()}ms.`),Ue.release(r);const n=(new Date).getTime()-o;return Pe.timeSpent+=n,Pe.spentAverage=Pe.timeSpent/++Pe.performedExports,q(4,`[pool] Work completed in ${n} ms.`),{result:s,options:t}}catch(e){throw++Pe.droppedExports,r&&Ue.release(r),new ue(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Fe(){const{min:e,max:t}=Ue;q(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),q(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),q(5,`[pool] The number of resources that are currently available: ${Ue.numFree()}.`),q(5,`[pool] The number of resources that are currently acquired: ${Ue.numUsed()}.`),q(5,`[pool] The number of callers waiting to acquire a resource: ${Ue.numPendingAcquires()}.`)}var Ve=()=>({min:Ue.min,max:Ue.max,available:Ue.numFree(),inUse:Ue.numUsed(),pendingAcquire:Ue.numPendingAcquires()}),We=()=>Pe;let qe=!1;const Be=async(e,t)=>{q(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Z(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=ae(t,e,A),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ne()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{q(4,"[chart] Attempting to export from a SVG input.");const e=ze(function(e){const t=new S("").window;return x(t).sanitize(e)}(r.payload.svg),r,t);return++Pe.exportFromSvgAttempts,e}catch(e){return t(new ue("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return q(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new ue("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return q(4,"[chart] Attempting to export from a raw input."),re(r.customLogic?.allowCodeExecution)?Je(r,t):"string"==typeof o.instr?ze(o.instr.trim(),r,t):Ke(r,o.instr||o.options,t)}catch(e){return t(new ue("[chart] Error loading raw input.").setError(e))}return t(new ue("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Xe=e=>{const{chart:t,exporting:r}=e.export?.options||Q(e.export?.instr),o=Q(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ke=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:qe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=Y(e.customLogic.resources,re(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=Y(t,re(e.customLogic.allowFileResources))}catch(e){B(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new ue("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=z(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=Q(i(s[e],"utf8"),!0):s[e]=Q(s[e],!0))}catch(t){s[e]={},B(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=oe(n.customCode,n.allowFileResources)}catch(e){B(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,B(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Xe(e)};try{return r(!1,await Me(s.strInj||t||o,e))}catch(e){return r(e)}},Je=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=ee(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ke(e,!1,t)}catch(r){return t(new ue(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},ze=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return q(4,"[chart] Parsing input as SVG."),Ke(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ke(t,o,r)}catch(e){return re(o)?Je(t,r):r(new ue("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Ye=[],Qe=()=>{q(4,"[server] Clearing all registered intervals.");for(const e of Ye)clearInterval(e)},Ze=(e,t,r,o)=>{B(1,e),"development"!==M.OTHER_NODE_ENV&&delete e.stack,o(e)},et=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var tt=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=k({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(q(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),q(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class rt extends ue{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const ot={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let it=0;const st=[],nt=[],at=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},lt=async(e,t,r)=>{try{const r=ie(),i=b().replace(/-/g,""),s=ne(),n=e.body,a=++it;let l=z(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new rt("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=Q(n.infile||n.options||n.data);if(!c&&!n.svg)throw q(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new rt("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=at(st,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),q(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:Q(n.globalOptions,!0),themeOptions:Q(n.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:Q(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=ee(c,u.customLogic.allowCodeExecution));const d=ae(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new rt("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Be(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&q(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return q(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new rt(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,at(nt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ot[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const ct=JSON.parse(i(l(J,"package.json"))),pt=new Date,ht=[];function ut(e){if(!e)return!1;var t;t=setInterval((()=>{const e=We(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ht.push(t),ht.length>30&&ht.shift()}),6e4),Ye.push(t),e.get("/health",((e,t)=>{const r=We(),o=ht.length,i=ht.reduce(((e,t)=>e+t),0)/ht.length;q(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:pt,uptime:Math.floor(((new Date).getTime()-pt.getTime())/1e3/60)+" minutes",version:ct.version,highchartsVersion:Ee(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ve(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const dt=new Map,mt=L();mt.disable("x-powered-by"),mt.use(R());const gt=_.memoryStorage(),ft=_({storage:gt,limits:{fieldSize:52428800}});mt.use(L.json({limit:52428800})),mt.use(L.urlencoded({extended:!0,limit:52428800})),mt.use(ft.none());const vt=e=>{e.on("clientError",(e=>{B(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{B(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{B(1,e,`[server] Socket error: ${e.message}`)}))}))},yt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(mt);vt(t),t.listen(e.port,e.host),dt.set(e.port,t),q(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){q(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},mt);vt(o),o.listen(e.ssl.port,e.host),dt.set(e.ssl.port,o),q(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&tt(mt,e.rateLimiting),mt.use(L.static(c.join(J,"public"))),ut(mt),(e=>{e.post("/",lt),e.post("/:filename",lt)})(mt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(J,"public","index.html"))}))})(mt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=M.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new rt("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new rt("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new rt("No new version supplied.",400);try{await be(i)}catch(e){throw new rt(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Ee(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(mt),(e=>{e.use(Ze),e.use(et)})(mt)}catch(e){throw new ue("[server] Could not configure and start the server.").setError(e)}},bt=()=>{q(4,"[server] Closing all servers.");for(const[e,t]of dt)t.close((()=>{q(4,`[server] Closed server on port: ${e}.`)}))};var wt={startServer:yt,closeServers:bt,getServers:()=>dt,enableRateLimiting:e=>tt(mt,e),getExpress:()=>L,getApp:()=>mt,use:(e,...t)=>{mt.use(e,...t)},get:(e,...t)=>{mt.get(e,...t)},post:(e,...t)=>{mt.post(e,...t)}};const Et=async e=>{await Promise.allSettled([Qe(),bt(),je()]),process.exit(e)};var Tt={server:wt,startServer:yt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=re(t),(e=>{X(e&&parseInt(e.level)),e&&e.dest&&K(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(q(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{q(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGTERM",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("SIGHUP",(async(e,t)=>{q(4,`The ${e} event with code: ${t}.`),await Et(0)})),process.on("uncaughtException",(async(e,t)=>{B(1,e,`The ${t} error.`),await Et(1)}))),await ve(e),await De({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Be(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await je()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Be({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await je()}catch(e){throw new ue("[chart] Error encountered during batch export.").setError(e)}},startExport:Be,setOptions:(e,t)=>(t?.length&&(se=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){B(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),le(I,se),se=ce(I),e&&(se=ae(se,e,A)),t?.length&&(se=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=re(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(q(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&te();return e}(se,t,I)),se),shutdownCleanUp:Et,log:q,logWithStack:B,setLogLevel:X,enableFileLogging:K,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=N[r]?N[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(C).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)C[e]=C[e].map((t=>({...t,section:e}))),n=[...n,...C[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=pe(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){B(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(J,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(J+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:te};export{Tt as default}; +import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},N=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?N(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};N(_),u.config();const A=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:A(O.core),HIGHCHARTS_MODULE_SCRIPTS:A(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:A(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:G(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:G(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:G(),SERVER_RATE_LIMITING_WINDOW:G(),SERVER_RATE_LIMITING_DELAY:G(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:G(),POOL_MAX_WORKERS:G(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:G(),POOL_CREATE_TIMEOUT:G(),POOL_DESTROY_TIMEOUT:G(),POOL_IDLE_TIMEOUT:G(),POOL_CREATE_RETRY_INTERVAL:G(),POOL_REAPER_INTERVAL:G(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:G(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:D.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;s(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Oe(e),e}async function Le(e,t=!1){try{t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Oe(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}async function Oe(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const _e=g.fileURLToPath(new URL(".",import.meta.url)),ke=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var Ie=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await ke(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await ke(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(_e,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o})))(e,u,d,"base64")}return await s(e),f}catch(t){return await s(e),t}};let Ce=!1;const Ne={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Pe={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>{if(Ae.workLimit&&++e.workCount>Ae.workLimit)return W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1;try{const{other:t}=ie();return await Le(e.page,t.hardResetPage),!0}catch{return!1}},destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},He=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ce)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ce=new y({...Pe,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ce.on("release",(async e=>{await Le(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ce.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ce.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function $e(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ce){for(const e of Ce.used)Ce.release(e.resource);Ce.destroyed||(await Ce.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const Ue=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ne.exportAttempts,Ae.benchmarking&&De(),!Ce)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ce.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await Ie(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ce.release(r);const a=(new Date).getTime()-i;return Ne.timeSpent+=a,Ne.spentAverage=Ne.timeSpent/++Ne.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ne.droppedExports,r&&Ce.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ge=()=>({min:Ce.min,max:Ce.max,all:Ce.numFree()+Ce.numUsed(),available:Ce.numFree(),used:Ce.numUsed(),pending:Ce.numPendingAcquires()});function De(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ge();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var je=Ge,Me=()=>Ne;let Fe=!1;const We=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Xe(function(e){const t=new E("").window;return T(t).sanitize(e)}(r.payload.svg),r,t);return++Ne.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Xe(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?Be(r,t):"string"==typeof o.instr?Xe(o.instr.trim(),r,t):qe(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ve=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},qe=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Fe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await Ue(s.strInj||t||o,e))}catch(e){return r(e)}},Be=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,qe(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Xe=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),qe(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return qe(t,o,r)}catch(e){return ee(o)?Be(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Ke=[],Je=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Ke)clearInterval(e)},ze=(e,t,r,o)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},Ye=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Qe=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Ze extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const et={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let tt=0;const rt=[],ot=[],it=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},st=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++tt;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Ze("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Ze("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=it(rt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Fe,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Ze("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await We(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Ze(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,it(ot,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",et[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const nt=JSON.parse(i(l(X,"package.json"))),at=new Date,lt=[];function ct(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Me(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;lt.push(t),lt.length>30&<.shift()}),6e4),Ke.push(t),e.get("/health",((e,t)=>{const r=Me(),o=lt.length,i=lt.reduce(((e,t)=>e+t),0)/lt.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:at,uptime:Math.floor(((new Date).getTime()-at.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:je(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const pt=new Map,ht=x();ht.disable("x-powered-by"),ht.use(S());const ut=R.memoryStorage(),dt=R({storage:ut,limits:{fieldSize:52428800}});ht.use(x.json({limit:52428800})),ht.use(x.urlencoded({extended:!0,limit:52428800})),ht.use(dt.none());const gt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},mt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(ht);gt(t),t.listen(e.port,e.host),pt.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},ht);gt(o),o.listen(e.ssl.port,e.host),pt.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Qe(ht,e.rateLimiting),ht.use(x.static(c.join(X,"public"))),ct(ht),(e=>{e.post("/",st),e.post("/:filename",st)})(ht),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(ht),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Ze("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Ze("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Ze("No new version supplied.",400);try{await ve(i)}catch(e){throw new Ze(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(ht),(e=>{e.use(ze),e.use(Ye)})(ht)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},ft=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of pt)t.close((()=>{pt.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var vt={startServer:mt,closeServers:ft,getServers:()=>pt,enableRateLimiting:e=>Qe(ht,e),getExpress:()=>x,getApp:()=>ht,use:(e,...t)=>{ht.use(e,...t)},get:(e,...t)=>{ht.get(e,...t)},post:(e,...t)=>{ht.post(e,...t)}};const yt=async e=>{await Promise.allSettled([Je(),ft(),$e()]),process.exit(e)};var bt={server:vt,startServer:mt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Fe=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await yt(1)}))),await me(e),await He({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await We(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await $e()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(We({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await $e()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:We,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:yt,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{bt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 7c3426d7..84e5b396 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/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 250,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\nimport path from 'node:path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\n// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328\r\n// Not ideal - leaves trash in the FS\r\nimport { randomBytes } from 'node:crypto';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst RANDOM_PID = randomBytes(64).toString('base64url');\r\nconst PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`);\r\nconst DATA_DIR = path.join(PUPPETEER_DIR, 'profile');\r\n\r\n// The minimal args to speed up the browser\r\nconst minimalArgs = [\r\n `--user-data-dir=${DATA_DIR}`,\r\n '--autoplay-policy=user-gesture-required',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=AudioServiceOutOfProcess',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--ignore-gpu-blacklist',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--use-mock-keychain'\r\n];\r\n\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nconst setPageContent = async (page) => {\r\n await page.setContent(template);\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => window.setupHighcharts());\r\n\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error

${error.toString()}`\r\n );\r\n });\r\n};\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport const clearPage = async (page, hardReset = false) => {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank');\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport const newPage = async () => {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n};\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport const create = async (puppeteerArgs) => {\r\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\r\n\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'new',\r\n userDataDir: './tmp/',\r\n args: allArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n};\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport const get = async () => {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n\r\n return browser;\r\n};\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport const close = async () => {\r\n // Close the browser when connnected\r\n if (browser?.isConnected()) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n};\r\n\r\nexport default {\r\n newPage,\r\n clearPage,\r\n get,\r\n close\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = (page, height, width, encoding) =>\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options) =>\r\n page.evaluate(\r\n // eslint-disable-next-line no-undef\r\n (chart, options) => window.triggerExport(chart, options),\r\n chart,\r\n options\r\n );\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const res of injectedResources) {\r\n await res.dispose();\r\n }\r\n\r\n // Reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Force a rAF\r\n // See https://github.com/puppeteer/puppeteer/issues/7507\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => requestAnimationFrame(() => {}));\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart));\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedResources.push(\r\n await page.addScriptTag({\r\n content: resources.js\r\n })\r\n );\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n try {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedResources.push(\r\n await page.addScriptTag(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n )\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The JS file ${file} cannot be loaded.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Load CSS\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n url: cssImportPath\r\n })\r\n );\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n path: path.join(__basedir, cssImportPath)\r\n })\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n })\r\n );\r\n }\r\n }\r\n\r\n // Get the real chart size\r\n const size = isSVG\r\n ? await page.$eval(\r\n '#chart-container svg:first-of-type',\r\n (element, scale) => ({\r\n chartHeight: element.height.baseVal.value * scale,\r\n chartWidth: element.width.baseVal.value * scale\r\n }),\r\n parseFloat(exportOptions.scale)\r\n )\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\r\n\r\n // Set the viewport for the first time\r\n // NOTE: the call to setViewport is expensive - can we get away with only\r\n // calling it once, e.g. moving this one into the isSVG condition below?\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n // Prepare a zoom callback for the next evaluate call\r\n const zoomCallback = isSVG\r\n ? // In case of SVG the zoom must be set directly for body\r\n (scale) => {\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n }\r\n : // No need for such scale manipulation in case of other types of exports\r\n () => {\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n };\r\n\r\n // Set the zoom accordingly\r\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\r\n\r\n // Get the clip region for the page\r\n const { height, width, x, y } = await getClipRegion(page);\r\n\r\n if (!isSVG) {\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n width: Math.round(width),\r\n height: Math.round(height),\r\n deviceScaleFactor: parseFloat(exportOptions.scale)\r\n });\r\n }\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Destroy old charts after the export is done\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n });\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Custom puppeteer arguments\r\nlet puppeteerArgs;\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n await clearPage(workerHandle.page, true);\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // The newest puppeteer arguments for the browser creation\r\n puppeteerArgs = config.puppeteerArgs;\r\n\r\n // Create a browser instance\r\n await createBrowser(puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n const acquireCounter = measureTime();\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when acquiring an available entry.'\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError('Error encountered during export.').setError(\r\n result\r\n );\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n available: pool.numFree(),\r\n inUse: pool.numUsed(),\r\n pendingAcquire: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max } = pool;\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently available: ${pool.numFree()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently acquired: ${pool.numUsed()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of callers waiting to acquire a resource: ${pool.numPendingAcquires()}.`\r\n );\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input);\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer?.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","setPageContent","page","setContent","addScriptTag","evaluate","setupHighcharts","$eval","element","errorMessage","_displayErrors","innerHTML","clearPage","hardReset","goto","document","body","newPage","setCacheEnabled","__basedir","setAsConfig","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportOptions","requestAnimationFrame","displayErrors","debugger","isSVG","d","svgTemplate","strInj","js","push","content","isLocal","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","Highcharts","charts","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","_resolve","setTimeout","createImage","pdf","createPDF","oldCharts","oldChart","destroy","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","puppeteerArgs","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","close","initPool","allArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","isConnected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","prop","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"srBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBACA,uBACA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,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,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,GACPC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/** Called when initing the page */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/** Create the actual chart */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful??\r\n window.isRenderComplete = false;\r\n\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n setOptions(JSON.parse(options.export.globalOptions));\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (page, height, width, encoding) => {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n try {\r\n const { other } = getOptions();\r\n await clearPage(workerHandle.page, other.hardResetPage);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input);\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","setContent","addScriptTag","path","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,6GACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file diff --git a/lib/browser.js b/lib/browser.js index e3973dc4..af18427c 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -14,67 +14,18 @@ See LICENSE file in root for details. import fs from 'fs'; import * as url from 'url'; -import path from 'node:path'; import puppeteer from 'puppeteer'; -// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328 -// Not ideal - leaves trash in the FS -import { randomBytes } from 'node:crypto'; - import { getCachePath } from './cache.js'; import { getOptions } from './config.js'; +import { setupHighcharts } from './highcharts.js'; import { log, logWithStack } from './logger.js'; import ExportError from './errors/ExportError.js'; -const RANDOM_PID = randomBytes(64).toString('base64url'); -const PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`); -const DATA_DIR = path.join(PUPPETEER_DIR, 'profile'); - -// The minimal args to speed up the browser -const minimalArgs = [ - `--user-data-dir=${DATA_DIR}`, - '--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' -]; - +// Get the template for the page const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); - const template = fs.readFileSync( __dirname + '/../templates/template.html', 'utf8' @@ -83,96 +34,20 @@ const template = fs.readFileSync( let browser; /** - * Sets the content for a Puppeteer Page using a predefined template - * and additional scripts. Also, sets the pageerror in order to catch - * and display errors from the window context. - * - * @param {Object} page - The Puppeteer Page object for which the content - * is being set. - */ -const setPageContent = async (page) => { - await page.setContent(template); - await page.addScriptTag({ path: `${getCachePath()}/sources.js` }); - // eslint-disable-next-line no-undef - await page.evaluate(() => window.setupHighcharts()); - - page.on('pageerror', async (error) => { - // TODO: Consider adding a switch here that turns on log(0) logging - // on page errors. - await page.$eval( - '#container', - (element, errorMessage) => { - // eslint-disable-next-line no-undef - if (window._displayErrors) { - element.innerHTML = errorMessage; - } - }, - `

Chart input data error

${error.toString()}` - ); - }); -}; - -/** - * Clears the content of a Puppeteer Page based on the specified mode. - * - * @param {Object} page - The Puppeteer Page object to be cleared. - * @param {boolean} hardReset - A flag indicating the type of clearing - * to be performed. If true, navigates to 'about:blank' and resets content - * and scripts. If false, clears the body content by setting a predefined HTML - * structure. - * - * @throws {Error} Logs thrown error if clearing the page content fails. - */ -export const clearPage = async (page, hardReset = false) => { - try { - if (hardReset) { - // Navigate to about:blank - await page.goto('about:blank'); - - // Set the content and and scripts again - await setPageContent(page); - } else { - // Clear body content - await page.evaluate(() => { - document.body.innerHTML = - '
'; - }); - } - } catch (error) { - logWithStack( - 2, - error, - '[browser] Could not clear the content of the page.' - ); - } -}; - -/** - * Creates a new Puppeteer Page within an existing browser instance. - * - * If the browser instance is not available, returns false. + * Retrieves the existing Puppeteer browser instance. * - * The function creates a new page, disables caching, sets content using - * setPageContent(), and returns the created Puppeteer Page. + * @returns {Promise} A Promise resolving to the Puppeteer browser + * instance. * - * @returns {(boolean|object)} Returns false if the browser instance is not - * available, or a Puppeteer Page object representing the newly created page. + * @throws {ExportError} Throws an ExportError if no valid browser has been + * created. */ -export const newPage = async () => { +export function get() { if (!browser) { - return false; + throw new ExportError('[browser] No valid browser has been created.'); } - - const page = await browser.newPage(); - - // Disable cache - await page.setCacheEnabled(false); - - // Set the content - await setPageContent(page); - - return page; -}; + return browser; +} /** * Creates a Puppeteer browser instance with the specified arguments. @@ -185,18 +60,18 @@ export const newPage = async () => { * @throws {ExportError} Throws an ExportError if max retries to open a browser * instance are reached, or if no browser instance is found after retries. */ -export const create = async (puppeteerArgs) => { - const allArgs = [...minimalArgs, ...(puppeteerArgs || [])]; - +export async function create(puppeteerArgs) { // Get the debug options const { enable: enabledDebug, ...debug } = getOptions().debug; const launchOptions = { - headless: 'new', + headless: 'shell', userDataDir: './tmp/', - args: allArgs, + args: puppeteerArgs, handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false, + waitForInitialPage: false, + defaultViewport: null, ...(enabledDebug && debug) }; @@ -233,7 +108,7 @@ export const create = async (puppeteerArgs) => { await open(); // Debug mode inform if (enabledDebug) { - log(3, `[browser] Lanuched browser in debug mode.`); + log(3, `[browser] Launched browser in debug mode.`); } } catch (error) { throw new ExportError( @@ -248,42 +123,107 @@ export const create = async (puppeteerArgs) => { // Return a browser promise return browser; -}; +} /** - * Retrieves the existing Puppeteer browser instance. + * Closes the Puppeteer browser instance if it is connected. * - * @returns {Promise} A Promise resolving to the Puppeteer browser - * instance. + * @returns {Promise} A Promise resolving to true after the browser + * is closed. + */ +export async function close() { + // Close the browser when connnected + if (browser?.connected) { + await browser.close(); + } + log(4, '[browser] Closed the browser.'); +} + +/** + * Creates a new Puppeteer Page within an existing browser instance. * - * @throws {ExportError} Throws an ExportError if no valid browser has been - * created. + * If the browser instance is not available, returns false. + * + * The function creates a new page, disables caching, sets content using + * setPageContent(), and returns the created Puppeteer Page. + * + * @returns {(boolean|object)} Returns false if the browser instance is not + * available, or a Puppeteer Page object representing the newly created page. */ -export const get = async () => { +export async function newPage() { if (!browser) { - throw new ExportError('[browser] No valid browser has been created.'); + return false; } - return browser; -}; + // Create a page + const page = await browser.newPage(); + + // Disable cache + await page.setCacheEnabled(false); + + // Set the content + await setPageContent(page); + + return page; +} /** - * Closes the Puppeteer browser instance if it is connected. + * Clears the content of a Puppeteer Page based on the specified mode. * - * @returns {Promise} A Promise resolving to true after the browser - * is closed. + * @param {Object} page - The Puppeteer Page object to be cleared. + * @param {boolean} hardReset - A flag indicating the type of clearing + * to be performed. If true, navigates to 'about:blank' and resets content + * and scripts. If false, clears the body content by setting a predefined HTML + * structure. + * + * @throws {Error} Logs thrown error if clearing the page content fails. */ -export const close = async () => { - // Close the browser when connnected - if (browser?.isConnected()) { - await browser.close(); +export async function clearPage(page, hardReset = false) { + try { + if (hardReset) { + // Navigate to about:blank + await page.goto('about:blank', { waitUntil: 'domcontentloaded' }); + + // Set the content and and scripts again + await setPageContent(page); + } else { + // Clear body content + await page.evaluate(() => { + document.body.innerHTML = + '
'; + }); + } + } catch (error) { + logWithStack( + 2, + error, + '[browser] Could not clear the content of the page.' + ); } - log(4, '[browser] Closed the browser.'); -}; +} + +/** + * Sets the content for a Puppeteer Page using a predefined template + * and additional scripts. Also, sets the pageerror in order to catch + * and display errors from the window context. + * + * @param {Object} page - The Puppeteer Page object for which the content + * is being set. + */ +async function setPageContent(page) { + await page.setContent(template, { waitUntil: 'domcontentloaded' }); + + // Add all registered Higcharts scripts, quite demanding + await page.addScriptTag({ path: `${getCachePath()}/sources.js` }); + + // Set the initial animObject + await page.evaluate(setupHighcharts); +} export default { - newPage, - clearPage, get, - close + create, + close, + newPage, + clearPage }; diff --git a/lib/envs.js b/lib/envs.js index dfdbd6cb..3b380b38 100644 --- a/lib/envs.js +++ b/lib/envs.js @@ -203,6 +203,7 @@ export const Config = z.object({ OTHER_NODE_ENV: v.enum(['development', 'production', 'test']), OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(), OTHER_NO_LOGO: v.boolean(), + OTHER_HARD_RESET_PAGE: v.boolean(), // debugger DEBUG_ENABLE: v.boolean(), diff --git a/lib/export.js b/lib/export.js index 5c09c4c1..e9d9a9f1 100644 --- a/lib/export.js +++ b/lib/export.js @@ -17,6 +17,7 @@ import path from 'path'; import * as url from 'url'; import cache from './cache.js'; +import { triggerExport } from './highcharts.js'; import { log, logWithStack } from './logger.js'; import svgTemplate from './../templates/svg_export/svg_export.js'; @@ -64,6 +65,10 @@ const createImage = (page, type, encoding, clip, rasterizationTimeout) => type, encoding, clip, + captureBeyondViewport: true, + fullPage: false, + optimizeForSpeed: true, + ...(type !== 'png' ? { quality: 80 } : {}), // #447, #463 - always render on a transparent page if the expected type // format is PNG @@ -88,13 +93,15 @@ const createImage = (page, type, encoding, clip, rasterizationTimeout) => * * @returns {Promise} Promise resolving to the PDF buffer. */ -const createPDF = (page, height, width, encoding) => - page.pdf({ +const createPDF = async (page, height, width, encoding) => { + await page.emulateMediaType('screen'); + return page.pdf({ // This will remove an extra empty page in PDF exports height: height + 1, width, encoding }); +}; /** * Creates an SVG string by evaluating the outerHTML of the first 'svg' element @@ -117,13 +124,8 @@ const createSVG = (page) => * * @returns {Promise} Promise resolving after the configuration is set. */ -const setAsConfig = (page, chart, options) => - page.evaluate( - // eslint-disable-next-line no-undef - (chart, options) => window.triggerExport(chart, options), - chart, - options - ); +const setAsConfig = (page, chart, options, displayErrors) => + page.evaluate(triggerExport, chart, options, displayErrors); /** * Exports to a chart from a page using Puppeteer. @@ -145,14 +147,31 @@ export default async (page, chart, options) => { /** Clear out all state set on the page with addScriptTag/addStyleTag. */ const clearInjected = async (page) => { - for (const res of injectedResources) { - await res.dispose(); + for (const resource of injectedResources) { + await resource.dispose(); } - // Reset all CSS and script tags + // Destroy old charts after export is done and reset all CSS and script tags await page.evaluate(() => { + // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG + // exports + if (typeof Highcharts !== 'undefined') { + // eslint-disable-next-line no-undef + const oldCharts = Highcharts.charts; + + // Check in any already existing charts + if (Array.isArray(oldCharts) && oldCharts.length) { + // Destroy old charts + for (const oldChart of oldCharts) { + oldChart && oldChart.destroy(); + // eslint-disable-next-line no-undef + Highcharts.charts.shift(); + } + } + } + // eslint-disable-next-line no-undef - const [, ...scriptsToRemove] = document.getElementsByTagName('script'); + const [...scriptsToRemove] = document.getElementsByTagName('script'); // eslint-disable-next-line no-undef const [, ...stylesToRemove] = document.getElementsByTagName('style'); // eslint-disable-next-line no-undef @@ -174,19 +193,11 @@ export default async (page, chart, options) => { const exportOptions = options.export; - // Force a rAF - // See https://github.com/puppeteer/puppeteer/issues/7507 - // eslint-disable-next-line no-undef - await page.evaluate(() => requestAnimationFrame(() => {})); - // Decide whether display error or debbuger wrapper around it const displayErrors = exportOptions?.options?.chart?.displayErrors && cache.getCache().activeManifest.modules.debugger; - // eslint-disable-next-line no-undef - await page.evaluate((d) => (window._displayErrors = d), displayErrors); - let isSVG; if ( chart.indexOf && @@ -201,7 +212,9 @@ export default async (page, chart, options) => { } isSVG = true; - await page.setContent(svgTemplate(chart)); + await page.setContent(svgTemplate(chart), { + waitUntil: 'domcontentloaded' + }); } else { // JSON config handling log(4, '[export] Treating as config.'); @@ -217,58 +230,59 @@ export default async (page, chart, options) => { width: exportOptions.width } }, - options + options, + displayErrors ); } else { // Basic configuration export chart.chart.height = exportOptions.height; chart.chart.width = exportOptions.width; - await setAsConfig(page, chart, options); + await setAsConfig(page, chart, options, displayErrors); } } // Use resources const resources = options.customLogic.resources; if (resources) { + const injectedJs = []; + // Load custom JS code if (resources.js) { - injectedResources.push( - await page.addScriptTag({ - content: resources.js - }) - ); + injectedJs.push({ + content: resources.js + }); } // Load scripts from all custom files if (resources.files) { for (const file of resources.files) { - try { - const isLocal = !file.startsWith('http') ? true : false; - - // Add each custom script from resources' files - injectedResources.push( - await page.addScriptTag( - isLocal - ? { - content: readFileSync(file, 'utf8') - } - : { - url: file - } - ) - ); - } catch (error) { - logWithStack( - 2, - error, - `[export] The JS file ${file} cannot be loaded.` - ); - } + const isLocal = !file.startsWith('http') ? true : false; + + // Add each custom script from resources' files + injectedJs.push( + isLocal + ? { + content: readFileSync(file, 'utf8') + } + : { + url: file + } + ); } } + for (const jsResource of injectedJs) { + try { + injectedResources.push(await page.addScriptTag(jsResource)); + } catch (error) { + logWithStack(2, error, `[export] The JS resource cannot be loaded.`); + } + } + injectedJs.length = 0; + // Load CSS + const injectedCss = []; if (resources.css) { let cssImports = resources.css.match(/@import\s*([^;]*);/g); if (cssImports) { @@ -286,44 +300,72 @@ export default async (page, chart, options) => { // Add each custom css from resources if (cssImportPath.startsWith('http')) { - injectedResources.push( - await page.addStyleTag({ - url: cssImportPath - }) - ); + injectedCss.push({ + url: cssImportPath + }); } else if (options.customLogic.allowFileResources) { - injectedResources.push( - await page.addStyleTag({ - path: path.join(__basedir, cssImportPath) - }) - ); + injectedCss.push({ + path: path.join(__basedir, cssImportPath) + }); } } } } // The rest of the CSS section will be content by now - injectedResources.push( - await page.addStyleTag({ - content: resources.css.replace(/@import\s*([^;]*);/g, '') || ' ' - }) - ); + injectedCss.push({ + content: resources.css.replace(/@import\s*([^;]*);/g, '') || ' ' + }); + + for (const cssResource of injectedCss) { + try { + injectedResources.push(await page.addStyleTag(cssResource)); + } catch (error) { + logWithStack( + 2, + error, + `[export] The CSS resource cannot be loaded.` + ); + } + } + injectedCss.length = 0; } } - // Get the real chart size + // Get the real chart size and set the zoom accordingly const size = isSVG - ? await page.$eval( - '#chart-container svg:first-of-type', - (element, scale) => ({ - chartHeight: element.height.baseVal.value * scale, - chartWidth: element.width.baseVal.value * scale - }), - parseFloat(exportOptions.scale) - ) + ? await page.evaluate((scale) => { + const svgElement = document.querySelector( + '#chart-container svg:first-of-type' + ); + + // Get the values correctly scaled + const chartHeight = svgElement.height.baseVal.value * scale; + const chartWidth = svgElement.width.baseVal.value * scale; + + // In case of SVG the zoom must be set directly for body + // Set the zoom as scale + // eslint-disable-next-line no-undef + document.body.style.zoom = scale; + + // Set the margin to 0px + // eslint-disable-next-line no-undef + document.body.style.margin = '0px'; + + return { + chartHeight, + chartWidth + }; + }, parseFloat(exportOptions.scale)) : await page.evaluate(() => { // eslint-disable-next-line no-undef const { chartHeight, chartWidth } = window.Highcharts.charts[0]; + + // No need for such scale manipulation in case of other types of exports + // Reset the zoom for other exports than to SVGs + // eslint-disable-next-line no-undef + document.body.style.zoom = 1; + return { chartHeight, chartWidth @@ -331,52 +373,19 @@ export default async (page, chart, options) => { }); // Set final height and width for viewport - const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height); - const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width); + const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height); + const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width); - // Set the viewport for the first time - // NOTE: the call to setViewport is expensive - can we get away with only - // calling it once, e.g. moving this one into the isSVG condition below? + // Get the clip region for the page + const { x, y } = await getClipRegion(page); + + // Set the final viewport now that we have the real height await page.setViewport({ height: viewportHeight, width: viewportWidth, deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale) }); - // Prepare a zoom callback for the next evaluate call - const zoomCallback = isSVG - ? // In case of SVG the zoom must be set directly for body - (scale) => { - // Set the zoom as scale - // eslint-disable-next-line no-undef - document.body.style.zoom = scale; - - // Set the margin to 0px - // eslint-disable-next-line no-undef - document.body.style.margin = '0px'; - } - : // No need for such scale manipulation in case of other types of exports - () => { - // Reset the zoom for other exports than to SVGs - // eslint-disable-next-line no-undef - document.body.style.zoom = 1; - }; - - // Set the zoom accordingly - await page.evaluate(zoomCallback, parseFloat(exportOptions.scale)); - - // Get the clip region for the page - const { height, width, x, y } = await getClipRegion(page); - - if (!isSVG) { - // Set the final viewport now that we have the real height - await page.setViewport({ - width: Math.round(width), - height: Math.round(height), - deviceScaleFactor: parseFloat(exportOptions.scale) - }); - } - let data; // RASTERIZATION if (exportOptions.type === 'svg') { @@ -405,26 +414,6 @@ export default async (page, chart, options) => { ); } - // Destroy old charts after the export is done - await page.evaluate(() => { - // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG - // exports - if (typeof Highcharts !== 'undefined') { - // eslint-disable-next-line no-undef - const oldCharts = Highcharts.charts; - - // Check in any already existing charts - if (Array.isArray(oldCharts) && oldCharts.length) { - // Destroy old charts - for (const oldChart of oldCharts) { - oldChart && oldChart.destroy(); - // eslint-disable-next-line no-undef - Highcharts.charts.shift(); - } - } - } - }); - await clearInjected(page); return data; } catch (error) { diff --git a/lib/highcharts.js b/lib/highcharts.js new file mode 100644 index 00000000..d586cbc3 --- /dev/null +++ b/lib/highcharts.js @@ -0,0 +1,135 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +/* eslint-disable no-undef */ + +/** Called when initing the page */ +export function setupHighcharts() { + Highcharts.animObject = function () { + return { duration: 0 }; + }; +} + +/** Create the actual chart */ +export function triggerExport(chartOptions, options, displayErrors) { + // Display errors flag taken from chart options nad debugger module + window._displayErrors = displayErrors; + + // Get required functions + const { getOptions, merge, setOptions, wrap } = Highcharts; + + // Create a separate object for a potential setOptions usages in order to + // prevent from polluting other exports that can happen on the same page + Highcharts.setOptionsObj = merge(false, {}, getOptions()); + + // Trigger custom code + if (options.customLogic.customCode) { + new Function(options.customLogic.customCode)(); + } + + // By default animation is disabled + const chart = { + animation: false + }; + + // When straight inject, the size is set through CSS only + if (options.export.strInj) { + chart.height = chartOptions.chart.height; + chart.width = chartOptions.chart.width; + } + + // NOTE: Is this used for anything useful?? + window.isRenderComplete = false; + + wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) { + // Override userOptions with image friendly options + userOptions = merge(userOptions, { + exporting: { + enabled: false + }, + plotOptions: { + series: { + label: { + enabled: false + } + } + }, + /* Expects tooltip in userOptions when forExport is true. + https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241 + */ + tooltip: {} + }); + + (userOptions.series || []).forEach(function (series) { + series.animation = false; + }); + + // Add flag to know if chart render has been called. + if (!window.onHighchartsRender) { + window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => { + window.isRenderComplete = true; + }); + } + + proceed.apply(this, [userOptions, cb]); + }); + + wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) { + proceed.apply(this, [chart, options]); + }); + + // Get the user options + const userOptions = options.export.strInj + ? new Function(`return ${options.export.strInj}`)() + : chartOptions; + + // Merge the globalOptions, themeOptions, options from the wrapped + // setOptions function and user options to create the final options object + const finalOptions = merge( + false, + JSON.parse(options.export.themeOptions), + userOptions, + // Placed it here instead in the init because of the size issues + { chart } + ); + + const finalCallback = options.customLogic.callback + ? new Function(`return ${options.customLogic.callback}`)() + : undefined; + + // Set the global options if exist + setOptions(JSON.parse(options.export.globalOptions)); + + Highcharts[options.export.constr || 'chart']( + 'container', + finalOptions, + finalCallback + ); + + // Get the current global options + const defaultOptions = getOptions(); + + // Clear it just in case (e.g. the setOptions was used in the customCode) + for (const prop in defaultOptions) { + if (typeof defaultOptions[prop] !== 'function') { + delete defaultOptions[prop]; + } + } + + // Set the default options back + setOptions(Highcharts.setOptionsObj); + + // Empty the custom global options object + Highcharts.setOptionsObj = {}; +} diff --git a/lib/index.js b/lib/index.js index 9745c66d..d398cc5d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -104,7 +104,7 @@ const initExport = async (options) => { minWorkers: 1, maxWorkers: 1 }, - puppeteerArgs: options.puppeteer?.args || [] + puppeteerArgs: options.puppeteer.args || [] }); // Return updated options diff --git a/lib/pool.js b/lib/pool.js index 87d8f6d3..887ef779 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -28,6 +28,9 @@ import { measureTime } from './utils.js'; import ExportError from './errors/ExportError.js'; +// The pool instance +let pool = false; + // Pool statistics export const stats = { performedExports: 0, @@ -40,12 +43,6 @@ export const stats = { let poolConfig = {}; -// The pool instance -let pool = false; - -// Custom puppeteer arguments -let puppeteerArgs; - const factory = { /** * Creates a new worker page for the export pool. @@ -89,6 +86,22 @@ const factory = { }); } + // Set the pageerror listener + page.on('pageerror', async (error) => { + // TODO: Consider adding a switch here that turns on log(0) logging + // on page errors. + await page.$eval( + '#container', + (element, errorMessage) => { + // eslint-disable-next-line no-undef + if (window._displayErrors) { + element.innerHTML = errorMessage; + } + }, + `

Chart input data error:

${error.toString()}` + ); + }); + return { id, page, @@ -120,8 +133,13 @@ const factory = { } // Clear page - await clearPage(workerHandle.page, true); - return true; + try { + const { other } = getOptions(); + await clearPage(workerHandle.page, other.hardResetPage); + return true; + } catch { + return false; + } }, /** @@ -130,12 +148,12 @@ const factory = { * @param {Object} workerHandle - The handle to the worker, containing * the worker's ID and a reference to the browser page. */ - destroy: (workerHandle) => { + destroy: async (workerHandle) => { log(3, `[pool] Destroying pool entry ${workerHandle.id}.`); if (workerHandle.page) { // We don't really need to wait around for this - workerHandle.page.close(); + await workerHandle.page.close(); } } }; @@ -151,11 +169,8 @@ export const initPool = async (config) => { // For the module scope usage poolConfig = config && config.pool ? { ...config.pool } : {}; - // The newest puppeteer arguments for the browser creation - puppeteerArgs = config.puppeteerArgs; - - // Create a browser instance - await createBrowser(puppeteerArgs); + // Create a browser instance with the puppeteer arguments + await createBrowser(config.puppeteerArgs); log( 3, @@ -284,9 +299,9 @@ export const postWork = async (chart, options) => { } // Acquire the worker along with the id of resource and work count + const acquireCounter = measureTime(); try { log(4, '[pool] Acquiring a worker handle.'); - const acquireCounter = measureTime(); workerHandle = await pool.acquire().promise; // Check the page acquire time @@ -301,7 +316,10 @@ export const postWork = async (chart, options) => { } } catch (error) { throw new ExportError( - 'Error encountered when acquiring an available entry.' + (options.payload?.requestId + ? `For request with ID ${options.payload?.requestId} - ` + : '') + + `Error encountered when acquiring an available entry: ${acquireCounter()}ms.` ).setError(error); } log(4, '[pool] Acquired a worker handle.'); @@ -329,9 +347,11 @@ export const postWork = async (chart, options) => { workerHandle.page = await browserNewPage(); } - throw new ExportError('Error encountered during export.').setError( - result - ); + throw new ExportError( + (options.payload?.requestId + ? `For request with ID ${options.payload?.requestId} - ` + : '') + `Error encountered during export: ${exportCounter()}ms.` + ).setError(result); } // Check the Puppeteer export time @@ -392,9 +412,10 @@ export const getPool = () => pool; export const getPoolInfoJSON = () => ({ min: pool.min, max: pool.max, + all: pool.numFree() + pool.numUsed(), available: pool.numFree(), - inUse: pool.numUsed(), - pendingAcquire: pool.numPendingAcquires() + used: pool.numUsed(), + pending: pool.numPendingAcquires() }); /** @@ -403,22 +424,14 @@ export const getPoolInfoJSON = () => ({ * requests. */ export function getPoolInfo() { - const { min, max } = pool; + const { min, max, all, available, used, pending } = getPoolInfoJSON(); log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`); log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`); - log( - 5, - `[pool] The number of resources that are currently available: ${pool.numFree()}.` - ); - log( - 5, - `[pool] The number of resources that are currently acquired: ${pool.numUsed()}.` - ); - log( - 5, - `[pool] The number of callers waiting to acquire a resource: ${pool.numPendingAcquires()}.` - ); + log(5, `[pool] The number of all created resources: ${all}.`); + log(5, `[pool] The number of available resources: ${available}.`); + log(5, `[pool] The number of acquired resources: ${used}.`); + log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`); } export default { diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 9dae72cd..83a49515 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -23,7 +23,7 @@ export const scriptsNames = { 'export-data', 'parallel-coordinates', 'accessibility', - 'annotations-advanced', + // 'annotations-advanced', 'boost-canvas', 'boost', 'data', @@ -57,7 +57,7 @@ export const scriptsNames = { 'series-label', 'solid-gauge', 'sonification', - 'stock-tools', + // 'stock-tools', 'streamgraph', 'sunburst', 'variable-pie', @@ -88,7 +88,55 @@ export const scriptsNames = { export const defaultConfig = { puppeteer: { args: { - value: [], + value: [ + '--allow-running-insecure-content', + '--ash-no-nudges', + '--autoplay-policy=user-gesture-required', + '--block-new-web-contents', + '--disable-accelerated-2d-canvas', + '--disable-background-networking', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-breakpad', + '--disable-checker-imaging', + '--disable-client-side-phishing-detection', + '--disable-component-extensions-with-background-pages', + '--disable-component-update', + '--disable-default-apps', + '--disable-dev-shm-usage', + '--disable-domain-reliability', + '--disable-extensions', + '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP', + '--disable-hang-monitor', + '--disable-ipc-flooding-protection', + '--disable-logging', + '--disable-notifications', + '--disable-offer-store-unmasked-wallet-cards', + '--disable-popup-blocking', + '--disable-print-preview', + '--disable-prompt-on-repost', + '--disable-renderer-backgrounding', + '--disable-search-engine-choice-screen', + '--disable-session-crashed-bubble', + '--disable-setuid-sandbox', + '--disable-site-isolation-trials', + '--disable-speech-api', + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only', + '--mute-audio', + '--no-default-browser-check', + '--no-first-run', + '--no-pings', + '--no-sandbox', + '--no-startup-window', + '--no-zygote', + '--password-store=basic', + '--process-per-tab', + '--use-mock-keychain' + ], type: 'string[]', description: 'Arguments array to send to Puppeteer.' } @@ -564,6 +612,12 @@ export const defaultConfig = { envLink: 'OTHER_NO_LOGO', description: 'Skip printing the logo on a startup. Will be replaced by a simple text.' + }, + hardResetPage: { + value: false, + type: 'boolean', + envLink: 'OTHER_HARD_RESET_PAGE', + description: 'Decides if the page content should be reset entirely.' } }, debug: { @@ -575,7 +629,7 @@ export const defaultConfig = { description: '.' }, headless: { - value: false, + value: true, type: 'boolean', envLink: 'DEBUG_HEADLESS', description: '.' @@ -599,7 +653,7 @@ export const defaultConfig = { description: '.' }, slowMo: { - value: 250, + value: 0, type: 'number', envLink: 'DEBUG_SLOW_MO', description: '.' @@ -975,6 +1029,12 @@ export const promptsConfig = { name: 'noLogo', message: 'Skip printing the logo on startup. Replaced by simple text', initial: defaultConfig.other.noLogo.value + }, + { + type: 'toggle', + name: 'hardResetPage', + message: 'Decides if the page content should be reset entirely', + initial: defaultConfig.other.hardResetPage.value } ], debug: [ diff --git a/lib/server/server.js b/lib/server/server.js index 907c63c7..45c03b86 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -197,6 +197,7 @@ export const closeServers = () => { log(4, `[server] Closing all servers.`); for (const [port, server] of activeServers) { server.close(() => { + activeServers.delete(port); log(4, `[server] Closed server on port: ${port}.`); }); } diff --git a/package-lock.json b/package-lock.json index 6923f7f1..34a2f52c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.0", + "dompurify": "^3.1.2", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0", @@ -20,10 +20,10 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.7.0", + "puppeteer": "^22.8.0", "tarn": "^3.0.2", "uuid": "^9.0.1", - "zod": "^3.23.4" + "zod": "^3.23.8" }, "bin": { "highcharts-export-server": "bin/cli.js" @@ -39,21 +39,12 @@ "lint-staged": "^15.2.2", "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.16.4" + "rollup": "^4.17.2" }, "engines": { "node": ">=18.12.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -89,21 +80,21 @@ } }, "node_modules/@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", + "@babel/generator": "^7.24.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -119,12 +110,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -196,16 +187,16 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -215,33 +206,33 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -257,9 +248,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } @@ -274,25 +265,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dev": true, "dependencies": { "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -366,9 +357,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -569,19 +560,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -599,13 +590,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1205,9 +1196,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.2.tgz", - "integrity": "sha512-hZ/JhxPIceWaGSEzUZp83/8M49CoxlkuThfTR7t4AoCu5+ZvJ3vktLm60Otww2TXeROB5igiZ8D9oPQh6ckBVg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", + "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", @@ -1278,9 +1269,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", - "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", "cpu": [ "arm" ], @@ -1291,9 +1282,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", - "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", "cpu": [ "arm64" ], @@ -1304,9 +1295,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", - "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", "cpu": [ "arm64" ], @@ -1317,9 +1308,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", - "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", "cpu": [ "x64" ], @@ -1330,9 +1321,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", - "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", "cpu": [ "arm" ], @@ -1343,9 +1334,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", - "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", "cpu": [ "arm" ], @@ -1356,9 +1347,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", - "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", "cpu": [ "arm64" ], @@ -1369,9 +1360,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", - "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", "cpu": [ "arm64" ], @@ -1382,9 +1373,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", - "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", "cpu": [ "ppc64" ], @@ -1395,9 +1386,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", - "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", "cpu": [ "riscv64" ], @@ -1408,9 +1399,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", - "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", "cpu": [ "s390x" ], @@ -1421,9 +1412,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", - "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", "cpu": [ "x64" ], @@ -1434,9 +1425,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", - "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", "cpu": [ "x64" ], @@ -1447,9 +1438,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", - "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", "cpu": [ "arm64" ], @@ -1460,9 +1451,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", - "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", "cpu": [ "ia32" ], @@ -1473,9 +1464,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", - "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", + "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", "cpu": [ "x64" ], @@ -1601,9 +1592,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", "devOptional": true, "dependencies": { "undici-types": "~5.26.4" @@ -2058,31 +2049,40 @@ "optional": true }, "node_modules/bare-fs": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.3.tgz", - "integrity": "sha512-amG72llr9pstfXOBOHve1WjiuKKAMnebcmMbPWDZ7BCevAoJLpugjuAPRsDINEyjT0a6tbaVx3DctkXIRbLuJw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.0.tgz", + "integrity": "sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==", "optional": true, "dependencies": { "bare-events": "^2.0.0", "bare-path": "^2.0.0", - "streamx": "^2.13.0" + "bare-stream": "^1.0.0" } }, "node_modules/bare-os": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz", - "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.3.0.tgz", + "integrity": "sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==", "optional": true }, "node_modules/bare-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.1.tgz", - "integrity": "sha512-OHM+iwRDRMDBsSW7kl3dO62JyHdBKO3B25FB9vNQBPcGHMo4+eA8Yj41Lfbk3pS/seDY+siNge0LdRTulAau/A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.2.tgz", + "integrity": "sha512-o7KSt4prEphWUHa3QUwCxUI00R86VdjiuxmJK0iNVDHYPGo+HsDaVCnqCmPbf/MiW1ok8F4p3m8RTHlWk8K2ig==", "optional": true, "dependencies": { "bare-os": "^2.1.0" } }, + "node_modules/bare-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-1.0.0.tgz", + "integrity": "sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==", + "optional": true, + "dependencies": { + "streamx": "^2.16.1" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2312,9 +2312,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001612", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", - "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "version": "1.0.30001617", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz", + "integrity": "sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==", "dev": true, "funding": [ { @@ -2393,9 +2393,9 @@ } }, "node_modules/chromium-bidi": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.17.tgz", - "integrity": "sha512-BqOuIWUgTPj8ayuBFJUYCCuwIcwjBsb3/614P7tt1bEPJ4i1M0kCdIl0Wi9xhtswBXnfO2bTpTMkHD71H8rJMg==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.19.tgz", + "integrity": "sha512-UA6zL77b7RYCjJkZBsZ0wlvCTD+jTjllZ8f6wdO4buevXgTZYjV+XLB9CiEa2OuuTGGTLnI7eN9I60YxuALGQg==", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "10.0.0", @@ -2429,9 +2429,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", "dev": true }, "node_modules/cli-cursor": { @@ -2960,9 +2960,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz", - "integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.2.tgz", + "integrity": "sha512-hLGGBI1tw5N8qTELr3blKjAML/LY4ANxksbS612UiJyDfyf/2D092Pvm+S7pmeTGJRqvlJkFzBoHBQKgQlOQVg==" }, "node_modules/dotenv": { "version": "16.4.5", @@ -2981,9 +2981,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.745", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", - "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==", + "version": "1.4.761", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.761.tgz", + "integrity": "sha512-PIbxpiJGx6Bb8dQaonNc6CGTRlVntdLg/2nMa1YhnrwYOORY9a3ZgGN0UQYE6lAcj/lkyduJN7BPt/JiY+jAQQ==", "dev": true }, "node_modules/emittery": { @@ -4076,12 +4076,13 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -4749,26 +4750,11 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4776,12 +4762,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -5283,26 +5263,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -5310,12 +5275,6 @@ "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -5918,26 +5877,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -5945,12 +5889,6 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -6168,26 +6106,11 @@ "node": ">=4" } }, - "node_modules/nodemon/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/nodemon/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -6207,12 +6130,6 @@ "node": ">=4" } }, - "node_modules/nodemon/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -6381,17 +6298,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -6826,15 +6743,15 @@ } }, "node_modules/puppeteer": { - "version": "22.7.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.7.0.tgz", - "integrity": "sha512-s1ulKFZKW3lwWCtNu0VrRLfRaanFHxIv7F8UFYpLo8dPTZcI4wB4EAOD0sKT3SKP+1Rsjodb9WFsK78yKQ6i9Q==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.0.tgz", + "integrity": "sha512-Z616wyTr0d7KpxmfcBG22rAkzuo/xzHJ3ycpu4KiJ3dZNHn/C1CpqcCwPlpiIIsmPojTAfWjo6EMR7M+AaC0Ww==", "hasInstallScript": true, "dependencies": { - "@puppeteer/browsers": "2.2.2", + "@puppeteer/browsers": "2.2.3", "cosmiconfig": "9.0.0", "devtools-protocol": "0.0.1273771", - "puppeteer-core": "22.7.0" + "puppeteer-core": "22.8.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -6844,15 +6761,15 @@ } }, "node_modules/puppeteer-core": { - "version": "22.7.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.7.0.tgz", - "integrity": "sha512-9Q+L3VD7cfhXnxv6AqwTHsVb/+/uXENByhPrgvwQ49wvzQwtf1d6b7v6gpoG3tpRdwYjxoV1eHTD8tFahww09g==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.0.tgz", + "integrity": "sha512-S5bWx3g/fNuyFxjZX9TkZMN07CEH47+9Zm6IiTl1QfqI9pnVaShbwrD9kRe5vmz/XPp/jLGhhxRUj1sY4wObnA==", "dependencies": { - "@puppeteer/browsers": "2.2.2", - "chromium-bidi": "0.5.17", + "@puppeteer/browsers": "2.2.3", + "chromium-bidi": "0.5.19", "debug": "4.3.4", "devtools-protocol": "0.0.1273771", - "ws": "8.16.0" + "ws": "8.17.0" }, "engines": { "node": ">=18" @@ -6950,9 +6867,9 @@ } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/readable-stream": { @@ -7120,9 +7037,9 @@ } }, "node_modules/rollup": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", - "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", + "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -7135,22 +7052,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.16.4", - "@rollup/rollup-android-arm64": "4.16.4", - "@rollup/rollup-darwin-arm64": "4.16.4", - "@rollup/rollup-darwin-x64": "4.16.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", - "@rollup/rollup-linux-arm-musleabihf": "4.16.4", - "@rollup/rollup-linux-arm64-gnu": "4.16.4", - "@rollup/rollup-linux-arm64-musl": "4.16.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", - "@rollup/rollup-linux-riscv64-gnu": "4.16.4", - "@rollup/rollup-linux-s390x-gnu": "4.16.4", - "@rollup/rollup-linux-x64-gnu": "4.16.4", - "@rollup/rollup-linux-x64-musl": "4.16.4", - "@rollup/rollup-win32-arm64-msvc": "4.16.4", - "@rollup/rollup-win32-ia32-msvc": "4.16.4", - "@rollup/rollup-win32-x64-msvc": "4.16.4", + "@rollup/rollup-android-arm-eabi": "4.17.2", + "@rollup/rollup-android-arm64": "4.17.2", + "@rollup/rollup-darwin-arm64": "4.17.2", + "@rollup/rollup-darwin-x64": "4.17.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", + "@rollup/rollup-linux-arm-musleabihf": "4.17.2", + "@rollup/rollup-linux-arm64-gnu": "4.17.2", + "@rollup/rollup-linux-arm64-musl": "4.17.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", + "@rollup/rollup-linux-riscv64-gnu": "4.17.2", + "@rollup/rollup-linux-s390x-gnu": "4.17.2", + "@rollup/rollup-linux-x64-gnu": "4.17.2", + "@rollup/rollup-linux-x64-musl": "4.17.2", + "@rollup/rollup-win32-arm64-msvc": "4.17.2", + "@rollup/rollup-win32-ia32-msvc": "4.17.2", + "@rollup/rollup-win32-x64-msvc": "4.17.2", "fsevents": "~2.3.2" } }, @@ -7423,26 +7340,11 @@ "node": ">=10" } }, - "node_modules/simple-update-notifier/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -7450,12 +7352,6 @@ "node": ">=10" } }, - "node_modules/simple-update-notifier/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -7858,9 +7754,9 @@ } }, "node_modules/terser": { - "version": "5.30.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", - "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", + "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -7964,9 +7860,9 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -8210,9 +8106,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz", + "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==", "dev": true, "funding": [ { @@ -8229,7 +8125,7 @@ } ], "dependencies": { - "escalade": "^3.1.1", + "escalade": "^3.1.2", "picocolors": "^1.0.0" }, "bin": { @@ -8429,6 +8325,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -8504,9 +8409,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "engines": { "node": ">=10.0.0" }, @@ -8640,9 +8545,9 @@ } }, "node_modules/zod": { - "version": "3.23.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.4.tgz", - "integrity": "sha512-/AtWOKbBgjzEYYQRNfoGKHObgfAZag6qUJX1VbHo2PRBgS+wfWagEY2mizjfyAPcGesrJOcx/wcl0L9WnVrHFw==", + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 30dc7025..34520e78 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "install": "node ./install.js", "prestart": "rm -rf tmp || del -rf tmp /Q && node ./node_modules/puppeteer/install.mjs", "start": "node ./bin/cli.js --enableServer 1 --logLevel 2", - "start:debug": "node ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", + "start:debug": "node --inspect-brk=9229 ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", + "start:debug-browser": "node ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", + "start:debug-node": "node --inspect-brk=9229 ./bin/cli.js --enableServer 1 --logLevel 4", "start:dev": "nodemon ./bin/cli.js --enableServer 1 --logLevel 4", "lint": "eslint ./ --fix", "cli-tests": "node ./tests/cli/cli_test_runner.js", @@ -49,12 +51,12 @@ "lint-staged": "^15.2.2", "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.16.4" + "rollup": "^4.17.2" }, "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.0", + "dompurify": "^3.1.2", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0", @@ -62,10 +64,10 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.7.0", + "puppeteer": "^22.8.0", "tarn": "^3.0.2", "uuid": "^9.0.1", - "zod": "^3.23.4" + "zod": "^3.23.8" }, "lint-staged": { "*.js": "npx eslint --cache --fix", diff --git a/templates/template.html b/templates/template.html index 99e1f089..3354c9ae 100644 --- a/templates/template.html +++ b/templates/template.html @@ -39,147 +39,4 @@
- - From 067e0266c3d3d24a21fbc15e66d4b8470c143304 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Mon, 13 May 2024 16:25:35 +0200 Subject: [PATCH 4/7] Small performance and other corrections. --- dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/browser.js | 26 ++-- lib/index.js | 12 +- lib/pool.js | 10 +- lib/sanitize.js | 2 +- lib/schemas/config.js | 2 +- package-lock.json | 239 ++----------------------------- package.json | 8 +- tests/cli/scenarios/constr.json | 2 +- tests/http/scenarios/constr.json | 3 - 12 files changed, 48 insertions(+), 264 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index c0050e71..2f726829 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(R[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(R[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),o.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=H;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=H;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([i[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else o=W(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const i=V(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:Z(i[e],n,r);var o;return i};function ee(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?ee(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in N&&void 0!==N[o.envLink]&&(o.value=N[o.envLink]))}))}function te(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:te(i);return t}function re(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=re(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function ie(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class oe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const o=await ie(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,i,o)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,i,o,n)=>{let s;const a=o.host,l=o.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...i.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,i,l),ne.hcVersion=se(ne),e.writeFileSync(o,ne.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:i,server:o}=r,n=t.join(F,i.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||i.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=i,u=n.length+c.length+p.length;r.version!==i.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(i,o.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ne.activeManifest=o,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(i,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:i,merge:o,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=o(!1,{},i()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=o(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;n(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const u=i();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await Ee(e),e}async function we(e,t=!1){try{t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Ee(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}async function Ee(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Te=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Se=(e,t,r,i)=>e.evaluate(me,t,r,i);var xe=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{U(4,"[export] Determining export path.");const a=o.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Se(r,{chart:{height:a.height,width:a.width}},o,l):(i.chart.height=a.height,i.chart.width=a.width,await Se(r,i,o,l));const p=o.customLogic.resources;if(p){const i=[];if(p.js&&i.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");i.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of i)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}i.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):o.customLogic.allowFileResources&&s.push({path:t.join(Te,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,i=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:i}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new oe("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new oe(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:i})))(r,h,d,"base64")}return await s(r),f}catch(e){return await s(r),e}};let Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new oe("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}const{debug:i}=Q();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Oe.workLimit/2))}},validate:async e=>{if(Oe.workLimit&&++e.workCount>Oe.workLimit)return U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Oe.workLimit}).`),!1;try{const{other:t}=Q();return await we(e.page,t.hardResetPage),!0}catch{return!1}},destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},ke=async e=>{if(Oe=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,i={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(i)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new oe("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Oe.minWorkers}, max ${Oe.maxWorkers}.`),Re)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Oe.minWorkers)>parseInt(Oe.maxWorkers)&&(Oe.minWorkers=Oe.maxWorkers);try{Re=new c.Pool({..._e,min:parseInt(Oe.minWorkers),max:parseInt(Oe.maxWorkers),acquireTimeoutMillis:Oe.acquireTimeout,createTimeoutMillis:Oe.createTimeout,destroyTimeoutMillis:Oe.destroyTimeout,idleTimeoutMillis:Oe.idleTimeout,createRetryIntervalMillis:Oe.createRetryInterval,reapIntervalMillis:Oe.reaperInterval,propagateCreateError:!1}),Re.on("release",(async e=>{await we(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Re.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Re.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(U(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Le.exportAttempts,Oe.benchmarking&&Ne(),!Re)throw new oe("Work received, but pool has not been started.");const i=J();try{U(4,"[pool] Acquiring a worker handle."),r=await Re.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${i()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${i()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await xe(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),Re.release(r);const a=(new Date).getTime()-o;return Le.timeSpent+=a,Le.spentAverage=Le.timeSpent/++Le.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Le.droppedExports,r&&Re.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ne(){const{min:e,max:t,all:r,available:i,used:o,pending:n}=Ae();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${i}.`),U(5,`[pool] The number of acquired resources: ${o}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Pe=Ae,He=()=>Le;let $e=!1;const Ue=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Fe(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e)}(i.payload.svg),i,r);return++Le.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Fe(i.export.instr.trim(),i,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(i.customLogic?.allowCodeExecution)?Ge(i,r):"string"==typeof o.instr?Fe(o.instr.trim(),i,r):De(i,o.instr||o.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},je=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),i=W(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},De=async(t,r,i,o)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:$e;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...je(t)};try{return i(!1,await Ce(n.strInj||r||o,t))}catch(e){return i(e)}},Ge=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=B(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,De(e,!1,t)}catch(r){return t(new oe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Fe=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),De(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return De(t,i,r)}catch(e){return z(i)?Ge(t,r):r(new oe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Me=[],qe=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Me)clearInterval(e)},We=(e,t,r,i)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,i(e)},Ve=(e,t,r,i)=>{const{statusCode:o,status:n,message:s,stack:a}=e,l=o||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Be=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=v({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),U(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Xe extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ke=0;const Je=[],Ye=[],Qe=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:s,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,s,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},Ze=async(e,t,r)=>{try{const r=J(),o=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++Ke;let l=M(s.type);if(!s||"object"==typeof(i=s)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Xe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Qe(Je,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:$e,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Xe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ue(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,Qe(Ye,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ze[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const et=JSON.parse(e.readFileSync(t.join(F,"package.json"))),tt=new Date,rt=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;rt.push(t),rt.length>30&&rt.shift()}),6e4),Me.push(t),e.get("/health",((e,t)=>{const r=He(),i=rt.length,o=rt.reduce(((e,t)=>e+t),0)/rt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:tt,uptime:Math.floor(((new Date).getTime()-tt.getTime())/1e3/60)+" minutes",version:et.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ot=new Map,nt=m();nt.disable("x-powered-by"),nt.use(g());const st=f.memoryStorage(),at=f({storage:st,limits:{fieldSize:52428800}});nt.use(m.json({limit:52428800})),nt.use(m.urlencoded({extended:!0,limit:52428800})),nt.use(at.none());const lt=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},ct=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(nt);lt(e),e.listen(r.port,r.host),ot.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},nt);lt(e),e.listen(r.ssl.port,r.host),ot.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Be(nt,r.rateLimiting),nt.use(m.static(t.posix.join(F,"public"))),it(nt),(e=>{e.post("/",Ze),e.post("/:filename",Ze)})(nt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(nt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Xe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Xe("No new version supplied.",400);try{await ue(o)}catch(e){throw new Xe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(nt),(e=>{e.use(We),e.use(Ve)})(nt)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},pt=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ot)t.close((()=>{ot.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var ut={startServer:ct,closeServers:pt,getServers:()=>ot,enableRateLimiting:e=>Be(nt,e),getExpress:()=>m,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const ht=async e=>{await Promise.allSettled([qe(),pt(),Ie()]),process.exit(e)};var dt={server:ut,startServer:ct,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,$e=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ht(1)}))),await ce(e),await ke({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ue(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Ue({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await Ie()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:Ue,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let i=!1;for(let o=0;o(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=z(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ht,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=re(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:X};module.exports=dt; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLE1lZGlhUm91dGVyLFRyYW5zbGF0ZSxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcmd1bWVudHMgYXJyYXkgdG8gc2VuZCB0byBQdXBwZXRlZXIuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNkblVSTDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZmxhZyB0byBkZXRlcm1pbmUgd2hldGhlciB0byByZWZldGNoIGFsbCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuLidcclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5LiBJdCBpcyB1c2VkIHRvIHN0b3JlIHRoZSBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbSBzY3JpcHRzLidcclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaW5wdXQgZmlsZSBzaG91bGQgaW5jbHVkZSBhIG5hbWUgYW5kIGEgdHlwZSAoanNvbiBvciBzdmcpLiBJdCBtdXN0IGJlIGNvcnJlY3RseSBmb3JtYXR0ZWQgYXMgYSBKU09OIG9yIFNWRyBmaWxlLidcclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQsIHByb3ZpZGVkIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiBvciBTVkcgZmlsZSwgd2lsbCBvdmVycmlkZSB0aGUgLS1pbmZpbGUgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBjb25zdHJ1Y3RvciB0byB1c2UuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAndGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBiZXR3ZWVuIDAuMSBhbmQgNS4wLidcclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgdGhlbWUgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5pdGlhdGVzIGEgYmF0Y2ggam9iIHdpdGggYSBzdHJpbmcgY29udGFpbmluZyBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIi4nXHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHJlbmRlcmluZyBhIHdlYnBhZ2UuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB3aGV0aGVyIHRoZSBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgaXMgYWxsb3dlZCBkdXJpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA4MDgwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGhlIGRlbGF5IGR1cmF0aW9uIGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0gbGltaXQuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50LidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5LidcclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246ICcuJ1xyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xyXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxyXG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcclxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxyXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxyXG4vLyAqIEluaXRpYWwgdmFsdWVcclxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2FyZ3MnLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfVxyXG4gIF0sXHJcbiAgaGlnaGNoYXJ0czogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdpbmRpY2F0b3JTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5pbmRpY2F0b3JTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmN1c3RvbVNjcmlwdHMudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZXhwb3J0OiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAndHlwZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb25zdHInLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcclxuICAgICAgbWluOiAwLjEsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgY3VzdG9tTG9naWM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgc2VydmVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2hvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgbG9nZ2luZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2xldmVsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxyXG4gICAgICByb3VuZDogMCxcclxuICAgICAgbWluOiAwLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2ZpbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCB0aGUgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZmlsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZGVzdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBsb2cgZmlsZXMuIEVuYWJsZXMgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHVpOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncm91dGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgb3RoZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnbm9kZUVudicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub2RlRW52LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGFyZFJlc2V0UGFnZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5oYXJkUmVzZXRQYWdlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBkZWJ1ZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmhlYWRsZXNzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2RldnRvb2xzJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGV2dG9vbHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Db25zb2xlJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcubGlzdGVuVG9Db25zb2xlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2R1bXBpbycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmR1bXBpby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzbG93TW8nLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5zbG93TW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVidWdnaW5nUG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRlYnVnZ2luZ1BvcnQudmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqXHJcbiAqIEBmaWxlb3ZlcnZpZXdcclxuICogVGhpcyBmaWxlIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgd2l0aCB0aGUgJ3pvZCdcclxuICogbGlicmFyeS4gVGhlIHBhcnNlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHRoZW4gZXhwb3J0ZWQgdG8gYmUgdXNlZFxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgXCJlbnZzXCIuIFdlIHNob3VsZCBub3QgdXNlIHByb2Nlc3MuZW52IGRpcmVjdGx5XHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxyXG4gKlxyXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxyXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IHNjcmlwdHNOYW1lcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuLy8gaW4gdGhlIENvbmZpZyBvYmplY3RcclxuY29uc3QgdiA9IHtcclxuICAvLyBTcGxpdHMgc3RyaW5nIHZhbHVlIGludG8gZWxlbWVudHMgaW4gYW4gYXJyYXksIHRyaW1zIGV2ZXJ5IGVsZW1lbnQsIGNoZWNrc1xyXG4gIC8vIGlmIGFuIGFycmF5IGlzIGNvcnJlY3QsIGlmIGl0IGlzIGVtcHR5LCBhbmQgaWYgaXQgaXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgYXJyYXk6IChmaWx0ZXJBcnJheSkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlXHJcbiAgICAgICAgICAuc3BsaXQoJywnKVxyXG4gICAgICAgICAgLm1hcCgodmFsdWUpID0+IHZhbHVlLnRyaW0oKSlcclxuICAgICAgICAgIC5maWx0ZXIoKHZhbHVlKSA9PiBmaWx0ZXJBcnJheS5pbmNsdWRlcyh2YWx1ZSkpXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgb25seSB0cnVlLCBmYWxzZSBhbmQgY29ycmVjdGx5IHBhcnNlIHRoZSB2YWx1ZSB0byBib29sZWFuXHJcbiAgLy8gb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSB1bmRlZmluZWRcclxuICBib29sZWFuOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbJ3RydWUnLCAnZmFsc2UnLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgPT09ICd0cnVlJyA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcGFzc2VkIHZhbHVlcyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgZW51bTogKHZhbHVlcykgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWy4uLnZhbHVlcywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIFRyaW1zIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNoZWNrcyBpZiBpdCBpcyBlbXB0eSBvciBjb250YWlucyBzdHJpbmdpZmllZFxyXG4gIC8vIHZhbHVlcyBzdWNoIGFzIGZhbHNlLCB1bmRlZmluZWQsIG51bGwsIE5hTiwgaWYgaXQgZG9lcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBzdHJpbmc6ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJ10uaW5jbHVkZXModmFsdWUpIHx8XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgZm9yYmlkZGVuIHZhbHVlcywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBvc2l0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIHBvc2l0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBwb3NpdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG5vbi1uZWdhdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlXHJcbiAgLy8gd2lsbCBiZSB1bmRlZmluZWRcclxuICBub25OZWdhdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKVxyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IENvbmZpZyA9IHoub2JqZWN0KHtcclxuICAvLyBoaWdoY2hhcnRzXHJcbiAgSElHSENIQVJUU19WRVJTSU9OOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT4gL14obGF0ZXN0fFxcZCsoXFwuXFxkKyl7MCwyfSkkLy50ZXN0KHZhbHVlKSB8fCB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlosIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpIHx8XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpIHx8XHJcbiAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIEhJR0hDSEFSVFNfQ0ROX1VSTC4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggaHR0cDovLyBvciBodHRwczovLywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuY29yZSksXHJcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMubW9kdWxlcyksXHJcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuaW5kaWNhdG9ycyksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdi5ib29sZWFuKCksXHJcbiAgSElHSENIQVJUU19DQUNIRV9QQVRIOiB2LnN0cmluZygpLFxyXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxyXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlclxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHNlcnZlciBzc2xcclxuICBTRVJWRVJfU1NMX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9GT1JDRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfUkVBUEVSX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBsb2dnZXJcclxuICBMT0dHSU5HX0xFVkVMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZSA9PT0gJycgfHxcclxuICAgICAgICAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPD0gNSksXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgTE9HR0lOR19MRVZFTC4gV2Ugb25seSBhY2NlcHQgdmFsdWVzIGZyb20gMCB0byA1IGFzIGxvZ2dpbmcgbGV2ZWxzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG4gIExPR0dJTkdfRklMRTogdi5zdHJpbmcoKSxcclxuICBMT0dHSU5HX0RFU1Q6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHVpXHJcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBVSV9ST1VURTogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gb3RoZXJcclxuICBPVEhFUl9OT0RFX0VOVjogdi5lbnVtKFsnZGV2ZWxvcG1lbnQnLCAncHJvZHVjdGlvbicsICd0ZXN0J10pLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9OT19MT0dPOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19TTE9XX01POiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgREVCVUdfREVCVUdHSU5HX1BPUlQ6IHYucG9zaXRpdmVOdW0oKVxyXG59KTtcclxuXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gQ29uZmlnLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxubGV0IGxvZ2dpbmcgPSB7XHJcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXHJcbiAgdG9Db25zb2xlOiB0cnVlLFxyXG4gIHRvRmlsZTogZmFsc2UsXHJcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxyXG4gIC8vIExvZyBsZXZlbHNcclxuICBsZXZlbHNEZXNjOiBbXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzBdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzFdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ25vdGljZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgLy8gTG9nIGxpc3RlbmVyc1xyXG4gIGxpc3RlbmVyczogW11cclxufTtcclxuXHJcbi8vIEdhdGhlciBpbml0IGxvZ2dpbmcgb3B0aW9uc1xyXG5mb3IgKGNvbnN0IFtrZXksIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZGVmYXVsdENvbmZpZy5sb2dnaW5nKSkge1xyXG4gIGxvZ2dpbmdba2V5XSA9IG9wdGlvbi52YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHMgdGhlXHJcbiAqIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nW119IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuY29uc3QgbG9nVG9GaWxlID0gKHRleHRzLCBwcmVmaXgpID0+IHtcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICAgIWV4aXN0c1N5bmMobG9nZ2luZy5kZXN0KSAmJiBta2RpclN5bmMobG9nZ2luZy5kZXN0KTtcclxuXHJcbiAgICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XHJcbiAgICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICAgIGFwcGVuZEZpbGUoXHJcbiAgICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxyXG4gICAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgICAoZXJyb3IpID0+IHtcclxuICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGU6ICR7ZXJyb3J9YCk7XHJcbiAgICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcclxuICogYGxldmVsYCB3aWxsIGJlIHBhc3NlZCBkaXJlY3RseSB0byBjb25zb2xlLmxvZywgYW5kL29yIHdpbGwgYmUgam9pbmVkXHJcbiAqIGFuZCBhcHBlbmRlZCB0byB0aGUgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nIGxldmVsXHJcbiAqIGFuZCB0aGUgcmVzdCBhcmUgc3RyaW5ncyB0byBidWlsZCBhIG1lc3NhZ2Ugd2l0aC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2cgPSAoLi4uYXJncykgPT4ge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIGFsb25nXHJcbiAqIHdpdGggdGhlIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZ1dpdGhTdGFjayA9IChuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpID0+IHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIElmIHRoZSBjdXN0b21NZXNzYWdlIGV4aXN0cywgd2Ugd2FudCB0byBkaXNwbGF5IHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID1cclxuICAgIGVycm9yLm1lc3NhZ2UgIT09IGVycm9yLnN0YWNrTWVzc2FnZSB8fCBlcnJvci5zdGFja01lc3NhZ2UgPT09IHVuZGVmaW5lZFxyXG4gICAgICA/IGVycm9yLnN0YWNrXHJcbiAgICAgIDogZXJyb3Iuc3RhY2suc3BsaXQoJ1xcbicpLnNsaWNlKDEpLmpvaW4oJ1xcbicpO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3QgdGV4dHMgPSBbbWFpbk1lc3NhZ2UsICdcXG4nLCBzdGFja01lc3NhZ2VdO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICBtYWluTWVzc2FnZVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgJ1xcbicsXHJcbiAgICAgICAgc3RhY2tNZXNzYWdlXHJcbiAgICAgIF0pXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXHJcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlIG9yIDUgPSBiZW5jaG1hcmspXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBuZXcgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xyXG4gIGlmIChuZXdMZXZlbCA+PSAwICYmIG5ld0xldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBuZXdMZXZlbDtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0Rlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgbG9nIGZpbGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcclxuICAvLyBVcGRhdGUgbG9nZ2luZyBvcHRpb25zXHJcbiAgbG9nZ2luZyA9IHtcclxuICAgIC4uLmxvZ2dpbmcsXHJcbiAgICBkZXN0OiBsb2dEZXN0IHx8IGxvZ2dpbmcuZGVzdCxcclxuICAgIGZpbGU6IGxvZ0ZpbGUgfHwgbG9nZ2luZy5maWxlLFxyXG4gICAgdG9GaWxlOiB0cnVlXHJcbiAgfTtcclxuXHJcbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiBsb2coMSwgJ1tsb2dnZXJdIEZpbGUgbG9nZ2luZyBpbml0aWFsaXphdGlvbjogbm8gcGF0aCBzdXBwbGllZC4nKTtcclxuICB9XHJcblxyXG4gIGlmICghbG9nZ2luZy5kZXN0LmVuZHNXaXRoKCcvJykpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCArPSAnLyc7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmcgLSBUaGUgbG9nZ2luZyBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0TG9nZ2luZyA9IChsb2dnaW5nKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsb2dnaW5nICYmIHBhcnNlSW50KGxvZ2dpbmcubGV2ZWwpKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXHJcbiAgaWYgKGxvZ2dpbmcgJiYgbG9nZ2luZy5kZXN0KSB7XHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgbG9nZ2luZy5kZXN0LFxyXG4gICAgICBsb2dnaW5nLmZpbGUgfHwgJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gdG8gdGhlIGxvZ2dpbmcgc3lzdGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBsaXN0ZW5lciBmdW5jdGlvbiB0byBiZSBhZGRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsaXN0ZW4gPSAoZm4pID0+IHtcclxuICBsb2dnaW5nLmxpc3RlbmVycy5wdXNoKGZuKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBUb2dnbGVzIHRoZSBzdGFuZGFyZCBvdXRwdXQgKGNvbnNvbGUpIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCAtIElmIHRydWUsIGVuYWJsZXMgY29uc29sZSBsb2dnaW5nOyBpZiBmYWxzZSxcclxuICogZGlzYWJsZXMgaXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9nZ2xlU1RET3V0ID0gKGVuYWJsZWQpID0+IHtcclxuICBsb2dnaW5nLnRvQ29uc29sZSA9IGVuYWJsZWQ7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBpbml0TG9nZ2luZyxcclxuICBsaXN0ZW4sXHJcbiAgdG9nZ2xlU1RET3V0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4uL2xpYi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuY29uc3QgTUFYX0JBQ0tPRkZfQVRURU1QVFMgPSA2O1xyXG5cclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCB0ZXh0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7UmVnRXhwfSBbcnVsZT0vXFxzXFxzKy9nXSAtIFRoZSByZWd1bGFyIGV4cHJlc3Npb24gcnVsZSB0byBtYXRjaFxyXG4gKiBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY2xlYXJlZCBhbmQgc3RhbmRhcmRpemVkIHRleHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJUZXh0ID0gKHRleHQsIHJ1bGUgPSAvXFxzXFxzKy9nLCByZXBsYWNlciA9ICcgJykgPT5cclxuICB0ZXh0LnJlcGxhY2VBbGwocnVsZSwgcmVwbGFjZXIpLnRyaW0oKTtcclxuXHJcbi8qKlxyXG4gKiBJbXBsZW1lbnRzIGFuIGV4cG9uZW50aWFsIGJhY2tvZmYgc3RyYXRlZ3kgZm9yIHJldHJ5aW5nIGEgZnVuY3Rpb24gdW50aWxcclxuICogYSBjZXJ0YWluIG51bWJlciBvZiBhdHRlbXB0cyBhcmUgcmVhY2hlZC5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuXHJcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uXHJcbiAqIGlmIHN1Y2Nlc3NmdWwuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcclxuICogaXMgcmVhY2hlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHBCYWNrb2ZmID0gYXN5bmMgKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXHJcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xyXG5cclxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVhcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBXYWl0ZWQgJHtkZWxheUluTXN9bXMgdW50aWwgbmV4dCBjYWxsIGZvciB0aGUgcmVzb3VyY2UgaWQ6ICR7YXJnc1swXX0uYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUcnkgYWdhaW5cclxuICAgIHJldHVybiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0LCAuLi5hcmdzKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZml4VHlwZSA9ICh0eXBlLCBvdXRmaWxlKSA9PiB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEZvcm1hdHNcclxuICBjb25zdCBmb3JtYXRzID0gWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ107XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IHJlc291cmNlcyAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC4gQ2FuIGJlIGVpdGhlclxyXG4gKiBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OIG9yIGEgcGF0aCB0byBhIEpTT04gZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBXaGV0aGVyIHRvIGFsbG93IGxvYWRpbmcgcmVzb3VyY2VzIGZyb21cclxuICogZmlsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8dW5kZWZpbmVkfSAtIFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciB1bmRlZmluZWQgaWYgbm8gdmFsaWRcclxuICogcmVzb3VyY2VzIGFyZSBmb3VuZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBoYW5kbGVSZXNvdXJjZXMgPSAocmVzb3VyY2VzID0gZmFsc2UsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZWFkRmlsZVN5bmMocmVzb3VyY2VzLCAndXRmOCcpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIFRyeSB0byBnZXQgSlNPTlxyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn07XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIGFuZCBwYXJzZXMgSlNPTiBkYXRhLiBDaGVja3MgaWYgcHJvdmlkZWQgZGF0YSBpcyBvciBjYW5cclxuICogYmUgYSBjb3JyZWN0IEpTT04uIElmIGEgcHJpbWl0aXZlIGlzIHByb3ZpZGVkLCBpdCBpcyBzdHJpbmdpZmllZCBhbmQgcmV0dXJuZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gZGF0YSAtIFRoZSBKU09OIGRhdGEgdG8gYmUgdmFsaWRhdGVkIGFuZCBwYXJzZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9TdHJpbmcgLSBXaGV0aGVyIHRvIHJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgSlNPTi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgcGFyc2VkIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLFxyXG4gKiBvciBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQ29ycmVjdEpTT04oZGF0YSwgdG9TdHJpbmcpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gaWYgbm90IGFscmVhZHkgYmVmb3JlIHBhcnNpbmdcclxuICAgIGNvbnN0IHBhcnNlZERhdGEgPSBKU09OLnBhcnNlKFxyXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcclxuICAgICk7XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXHJcbiAgICBpZiAodHlwZW9mIHBhcnNlZERhdGEgIT09ICdzdHJpbmcnICYmIHRvU3RyaW5nKSB7XHJcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXJzZWREYXRhKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gYSBKU09OXHJcbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcclxuICB9IGNhdGNoIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3QgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiYgaXRlbSAhPT0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0RW1wdHkgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gIGl0ZW0gIT09IG51bGwgJiZcclxuICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDA7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2VcclxuICogb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgPSAoaXRlbSkgPT4ge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgdGhlIGdpdmVuIG9iamVjdCBvciBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IG9iaiAtIFRoZSBvYmplY3Qgb3IgYXJyYXkgdG8gYmUgZGVlcGx5IGNvcGllZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxBcnJheX0gLSBUaGUgZGVlcCBjb3B5IG9mIHRoZSBwcm92aWRlZCBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVlcENvcHkgPSAob2JqKSA9PiB7XHJcbiAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iajtcclxuICB9XHJcblxyXG4gIGNvbnN0IGNvcHkgPSBBcnJheS5pc0FycmF5KG9iaikgPyBbXSA6IHt9O1xyXG5cclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSB7XHJcbiAgICAgIGNvcHlba2V5XSA9IGRlZXBDb3B5KG9ialtrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBjb3B5O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZyB3aXRoIHRoZVxyXG4gKiBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBvcHRpb25zU3RyaW5naWZ5ID0gKG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zKSA9PiB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChuYW1lLCB2YWx1ZSkgPT4ge1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcblxyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChcclxuICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCcpKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JylcclxuICAgICAgKSB7XHJcbiAgICAgICAgdmFsdWUgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJ1xyXG4gICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICA6IHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG5vTG9nbyAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHZlcnNpb24gaW5mb3JtYXRpb24gd2l0aG91dFxyXG4gKiB0aGUgbG9nby5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwcmludExvZ28gPSAobm9Mb2dvKSA9PiB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cclxuICBjb25zdCBwYWNrYWdlVmVyc2lvbiA9IEpTT04ucGFyc2UoXHJcbiAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSlcclxuICApLnZlcnNpb247XHJcblxyXG4gIC8vIFByaW50IHRleHQgb25seVxyXG4gIGlmIChub0xvZ28pIHtcclxuICAgIGNvbnNvbGUubG9nKGBTdGFydGluZyBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdiR7cGFja2FnZVZlcnNpb259Li4uYCk7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBQcmludCB0aGUgbG9nb1xyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvbXNnL3N0YXJ0dXAubXNnJykudG9TdHJpbmcoKS5ib2xkLnllbGxvdyxcclxuICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgYWJzb2x1dGVQcm9wcyxcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZEFyZ3MsXHJcbiAgcHJvbXB0c0NvbmZpZ1xyXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGRlZXBDb3B5LCBpc09iamVjdCwgcHJpbnRVc2FnZSwgdG9Cb29sZWFuIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRPcHRpb25zID0gKCkgPT4gZ2VuZXJhbE9wdGlvbnM7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHNldHMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIHNlcnZlciBpbnN0YWNlLCBrZWVwaW5nXHJcbiAqIHRoZSBwcmluY2lwbGUgb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eS4gSXQgYWNjZXB0cyBvcHRpb25hbCB1c2VyT3B0aW9uc1xyXG4gKiBhbmQgYXJncyBmcm9tIHRoZSBDTEkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1c2VyT3B0aW9ucyAtIFVzZXItcHJvdmlkZWQgb3B0aW9ucyBmb3IgY3VzdG9taXphdGlvbi5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxyXG4gKiAoQ0xJIHVzYWdlKS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRPcHRpb25zID0gKHVzZXJPcHRpb25zLCBhcmdzKSA9PiB7XHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIEdldCB0aGUgYWRkaXRpb25hbCBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGZpbGVcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcclxuICB1cGRhdGVEZWZhdWx0Q29uZmlnKGRlZmF1bHRDb25maWcsIGdlbmVyYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXHJcbiAgZ2VuZXJhbE9wdGlvbnMgPSBpbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcclxuICBpZiAodXNlck9wdGlvbnMpIHtcclxuICAgIC8vIE1lcmdlIHVzZXIgb3B0aW9uc1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICB1c2VyT3B0aW9ucyxcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBwYWlyQXJndW1lbnRWYWx1ZShnZW5lcmFsT3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gZmluYWwgZ2VuZXJhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFsbG93cyBtYW51YWwgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBzcGVjaWZpZWQgcHJvbXB0cyBhbmQgc2F2ZXNcclxuICogdGhlIGNvbmZpZ3VyYXRpb24gdG8gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBvbmNlIHRoZSBtYW51YWxcclxuICogY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZWQgYW5kIHNhdmVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hbnVhbENvbmZpZyA9IGFzeW5jIChjb25maWdGaWxlTmFtZSkgPT4ge1xyXG4gIC8vIFByZXBhcmUgYSBjb25maWcgb2JqZWN0XHJcbiAgbGV0IGNvbmZpZ0ZpbGUgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgY29uZmlnIGZpbGUgZXhpc3RzXHJcbiAgaWYgKGV4aXN0c1N5bmMoY29uZmlnRmlsZU5hbWUpKSB7XHJcbiAgICBjb25maWdGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnRmlsZU5hbWUsICd1dGY4JykpO1xyXG4gIH1cclxuXHJcbiAgLy8gUXVlc3Rpb24gYWJvdXQgYSBjb25maWd1cmF0aW9uIGNhdGVnb3J5XHJcbiAgY29uc3Qgb25TdWJtaXQgPSBhc3luYyAocCwgY2F0ZWdvcmllcykgPT4ge1xyXG4gICAgbGV0IHF1ZXN0aW9uc0NvdW50ZXIgPSAwO1xyXG4gICAgbGV0IGFsbFF1ZXN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gdGhlIG1hbnVhbENvbmZpZyBvYmplY3RcclxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBjYXRlZ29yaWVzKSB7XHJcbiAgICAgIC8vIE1hcmsgZWFjaCBvcHRpb24gd2l0aCBhIHNlY3Rpb25cclxuICAgICAgcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXSA9IHByb21wdHNDb25maWdbc2VjdGlvbl0ubWFwKChvcHRpb24pID0+ICh7XHJcbiAgICAgICAgLi4ub3B0aW9uLFxyXG4gICAgICAgIHNlY3Rpb25cclxuICAgICAgfSkpO1xyXG5cclxuICAgICAgLy8gQ29sbGVjdCB0aGUgcXVlc3Rpb25zXHJcbiAgICAgIGFsbFF1ZXN0aW9ucyA9IFsuLi5hbGxRdWVzdGlvbnMsIC4uLnByb21wdHNDb25maWdbc2VjdGlvbl1dO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IHByb21wdHMoYWxsUXVlc3Rpb25zLCB7XHJcbiAgICAgIG9uU3VibWl0OiBhc3luYyAocHJvbXB0LCBhbnN3ZXIpID0+IHtcclxuICAgICAgICAvLyBHZXQgdGhlIGRlZmF1bHQgbW9kdWxlIHNjcmlwdHNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVTY3JpcHRzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcblxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgdXBkYXRlRGVmYXVsdENvbmZpZyhlbnRyeSwgY3VzdG9tVmFsdWUsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYSBjdXN0b20gSlNPTiBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY3VzdG9tVmFsdWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gY3VzdG9tVmFsdWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhbiBlbnYgdmFyaWFibGUgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZzW2VudHJ5LmVudkxpbmtdICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGVudnNbZW50cnkuZW52TGlua107XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkIGl0ZW1zLCBzZXR0aW5nIHZhbHVlcyBmcm9tXHJcbiAqIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbXMgLSBDb25maWd1cmF0aW9uIGl0ZW1zIHRvIGJlIHVzZWQgZm9yIGluaXRpYWxpemluZ1xyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGluaXRPcHRpb25zKGl0ZW1zKSB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhpdGVtcykpIHtcclxuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcclxuICAgICAgPyBpdGVtLnZhbHVlXHJcbiAgICAgIDogaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgfVxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUGFpcnMgYXJndW1lbnQgdmFsdWVzIHdpdGggY29ycmVzcG9uZGluZyBvcHRpb25zIGluIHRoZSBjb25maWd1cmF0aW9uLFxyXG4gKiB1cGRhdGluZyB0aGUgb3B0aW9ucyBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCB0byBiZSB1cGRhdGVkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBjb250YWluaW5nIHZhbHVlcyBmb3Igc3BlY2lmaWNcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGRlZmF1bHRDb25maWcgLSBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByZWZlcmVuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBwYWlyQXJndW1lbnRWYWx1ZShvcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKSB7XHJcbiAgbGV0IHNob3dVc2FnZSA9IGZhbHNlO1xyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gYXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkQXJnc1tvcHRpb25dLnNwbGl0KCcuJylcclxuICAgICAgOiBbXTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNvcnJlY3QgdHlwZSBmb3IgQ0xJIGFyZ3Mgd2hpY2ggYXJlIHBhc3NlZCBhcyBzdHJpbmdzXHJcbiAgICBsZXQgYXJndW1lbnRUeXBlO1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgYXJndW1lbnRUeXBlID0gb2JqW3Byb3BdLnR5cGU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIC8vIEZpbmRzIGFuIG9wdGlvbiBhbmQgc2V0IGEgY29ycmVzcG9uZGluZyB2YWx1ZVxyXG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgICAgaWYgKGFyZ3NbKytpXSkge1xyXG4gICAgICAgICAgICBpZiAoYXJndW1lbnRUeXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSB0b0Jvb2xlYW4oYXJnc1tpXSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlID09PSAnbnVtYmVyJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9ICthcmdzW2ldO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZS5pbmRleE9mKCddJykgPj0gMCkge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV0uc3BsaXQoJywnKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlICcke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHNob3dVc2FnZSA9IHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBvcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIERpc3BsYXkgdGhlIHVzYWdlIGZvciB0aGUgcmVmZXJlbmNlIGlmIG5lZWRlZFxyXG4gIGlmIChzaG93VXNhZ2UpIHtcclxuICAgIHByaW50VXNhZ2UoZGVmYXVsdENvbmZpZyk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IHVwZGF0ZXMgcHJvcGVydGllcyBpbiBhbiBvYmplY3QgYmFzZWQgb24gbmVzdGVkIG5hbWVzIGFuZCBhc3NpZ25zXHJcbiAqIHRoZSBmaW5hbCB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFRvVXBkYXRlIC0gVGhlIG9iamVjdCB0byBiZSB1cGRhdGVkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBuZXN0ZWROYW1lcyAtIEFycmF5IG9mIG5lc3RlZCBwcm9wZXJ0eSBuYW1lcy5cclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIGZpbmFsIHZhbHVlIHRvIGJlIGFzc2lnbmVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9iamVjdCB3aXRoIGFzc2lnbmVkIHZhbHVlcy5cclxuICovXHJcbmZ1bmN0aW9uIHJlY3Vyc2l2ZVByb3BzKG9iamVjdFRvVXBkYXRlLCBuZXN0ZWROYW1lcywgdmFsdWUpIHtcclxuICB3aGlsZSAobmVzdGVkTmFtZXMubGVuZ3RoID4gMSkge1xyXG4gICAgY29uc3QgcHJvcE5hbWUgPSBuZXN0ZWROYW1lcy5zaGlmdCgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHByb3BlcnR5IGluIG9iamVjdCBpZiBpdCBkb2Vzbid0IGV4aXN0XHJcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3RUb1VwZGF0ZSwgcHJvcE5hbWUpKSB7XHJcbiAgICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHt9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENhbGwgZnVuY3Rpb24gYWdhaW4gaWYgdGhlcmUgc3RpbGwgbmFtZXMgdG8gZ29cclxuICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0pLFxyXG4gICAgICBuZXN0ZWROYW1lcyxcclxuICAgICAgdmFsdWVcclxuICAgICk7XHJcblxyXG4gICAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG4gIH1cclxuXHJcbiAgLy8gQXNzaWduIHRoZSBmaW5hbCB2YWx1ZVxyXG4gIG9iamVjdFRvVXBkYXRlW25lc3RlZE5hbWVzWzBdXSA9IHZhbHVlO1xyXG4gIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWVyZ2VDb25maWdPcHRpb25zLFxyXG4gIGluaXRFeHBvcnRTZXR0aW5nc1xyXG59O1xyXG4iLCIvKipcclxuICogVGhpcyBtb2R1bGUgZXhwb3J0cyB0d28gZnVuY3Rpb25zOiBmZXRjaCAoZm9yIEdFVCByZXF1ZXN0cykgYW5kIHBvc3QgKGZvciBQT1NUIHJlcXVlc3RzKS5cclxuICovXHJcblxyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuY29uc3QgZ2V0UHJvdG9jb2wgPSAodXJsKSA9PiAodXJsLnN0YXJ0c1dpdGgoJ2h0dHBzJykgPyBodHRwcyA6IGh0dHApO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0XHJcbiAqIHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuXHJcbiAgICBwcm90b2NvbFxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgZGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIWRhdGEpIHtcclxuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XHJcbiAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gc2VuZCB0aGUgUE9TVCByZXF1ZXN0IHRvLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gYm9keSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0XHJcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXHJcbiAqIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXEgPSBwcm90b2NvbFxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgcmVzLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3QuXHJcbiAgICByZXEud3JpdGUoZGF0YSk7XHJcbiAgICByZXEuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZldGNoO1xyXG5leHBvcnQgeyBmZXRjaCwgcG9zdCB9O1xyXG4iLCJjbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlKSB7XHJcbiAgICBzdXBlcigpO1xyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuICB9XHJcblxyXG4gIHNldEVycm9yKGVycm9yKSB7XHJcbiAgICB0aGlzLmVycm9yID0gZXJyb3I7XHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gVGhlIGNhY2hlIG1hbmFnZXIgbWFuYWdlcyB0aGUgSGlnaGNoYXJ0cyBsaWJyYXJ5IGFuZCBpdHMgZGVwZW5kZW5jaWVzLlxyXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXHJcbi8vIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmljZVxyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0VmVyc2lvbiA9IChjYWNoZSkgPT4ge1xyXG4gIHJldHVybiBjYWNoZS5zb3VyY2VzXHJcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0TW9kdWxlTmFtZSA9IChzY3JpcHRQYXRoKSA9PiB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzLXJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIG1hcHBlZCBuYW1lcyBvZlxyXG4gKiBmZXRjaGVkIEhpZ2hjaGFydHMgbW9kdWxlcyB0byB1c2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlIHdyaXRpbmdcclxuICogdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxyXG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlXHJcbiAqIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZldGNoQW5kUHJvY2Vzc1NjcmlwdCA9IGFzeW5jIChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikgPT4ge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcblxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvcmVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tU2NyaXB0cyAtIEFycmF5IG9mIGN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2hcclxuICogKGZ1bGwgVVJMcykuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm94eU9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvclxyXG4gKiBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZldGNoU2NyaXB0cyA9IGFzeW5jIChcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikgPT4ge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBwcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBwcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcclxuICAgICAgICBlcnJvclxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXHJcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBwcm94eUFnZW50XHJcbiAgICA/IHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBlbnZzLlNFUlZFUl9QUk9YWV9USU1FT1VUXHJcbiAgICAgIH1cclxuICAgIDoge307XHJcblxyXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXHJcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucylcclxuICAgIClcclxuICBdO1xyXG5cclxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xyXG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XHJcbn07XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBzb3VyY2VQYXRoXHJcbikgPT4ge1xyXG4gIGNvbnN0IHZlcnNpb24gPSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9IHZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICF2ZXJzaW9uID8gJycgOiBgJHt2ZXJzaW9ufS9gO1xyXG4gIGNvbnN0IGNkblVSTCA9IGhpZ2hjaGFydHNPcHRpb25zLmNkblVSTCB8fCBjYWNoZS5jZG5VUkw7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuICB0cnkge1xyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IGZldGNoU2NyaXB0cyhcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufSR7Y31gKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGAke2NkblVSTH1tYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICksXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoXHJcbiAgICAgICAgICAoaSkgPT4gYCR7Y2RuVVJMfXN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xyXG4gKiB0aGUgY2FjaGUgZm9yIHRoZSBuZXcgdmVyc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5ld1ZlcnNpb24gLSBUaGUgbmV3IEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSBhcHBsaWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwob2JqZWN0fGJvb2xlYW4pPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZFxyXG4gKiBjb25maWd1cmF0aW9uIHdpdGggdGhlIG5ldyB2ZXJzaW9uLCBvciBmYWxzZSBpZiBubyBhcHBsaWVkIGNvbmZpZ3VyYXRpb25cclxuICogZXhpc3RzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVwZGF0ZVZlcnNpb24gPSBhc3luYyAobmV3VmVyc2lvbikgPT4ge1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcbiAgaWYgKG9wdGlvbnM/LmhpZ2hjaGFydHMpIHtcclxuICAgIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcclxuICB9XHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXHJcbiAqIGFuZCB1cGRhdGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgaGlnaGNoYXJ0cywgc2VydmVyIH0gPSBvcHRpb25zO1xyXG4gIGNvbnN0IGNhY2hlUGF0aCA9IGpvaW4oX19kaXJuYW1lLCBoaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoKTtcclxuXHJcbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiBtYW5pZmVzdC5qc29uIGRvZXMgbm90IGV4aXN0XHJcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcclxuICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHM7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBoaWdoY2hhcnRzIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGhpZ2hjaGFydHMudmVyc2lvbikge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXMpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gVGhlIGNhY2hlIGFuZCB0aGUgcmVxdWVzdGVkIG1vZHVsZXMgZG8gbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHMsIGZldGNoZWRNb2R1bGVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZVBhdGggPSAoKSA9PlxyXG4gIGpvaW4oX19kaXJuYW1lLCBnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoLFxyXG4gIHVwZGF0ZVZlcnNpb24sXHJcbiAgZ2V0Q2FjaGU6ICgpID0+IGNhY2hlLFxyXG4gIGhpZ2hjaGFydHM6ICgpID0+IGNhY2hlLnNvdXJjZXMsXHJcbiAgdmVyc2lvbjogKCkgPT4gY2FjaGUuaGNWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKiogQ3JlYXRlIHRoZSBhY3R1YWwgY2hhcnQgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRyaWdnZXJFeHBvcnQoY2hhcnRPcHRpb25zLCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSB7XHJcbiAgLy8gRGlzcGxheSBlcnJvcnMgZmxhZyB0YWtlbiBmcm9tIGNoYXJ0IG9wdGlvbnMgbmFkIGRlYnVnZ2VyIG1vZHVsZVxyXG4gIHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGRpc3BsYXlFcnJvcnM7XHJcblxyXG4gIC8vIEdldCByZXF1aXJlZCBmdW5jdGlvbnNcclxuICBjb25zdCB7IGdldE9wdGlvbnMsIG1lcmdlLCBzZXRPcHRpb25zLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGEgcG90ZW50aWFsIHNldE9wdGlvbnMgdXNhZ2VzIGluIG9yZGVyIHRvXHJcbiAgLy8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBUcmlnZ2VyIGN1c3RvbSBjb2RlXHJcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkoKTtcclxuICB9XHJcblxyXG4gIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgY29uc3QgY2hhcnQgPSB7XHJcbiAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XHJcbiAgaWYgKG9wdGlvbnMuZXhwb3J0LnN0ckluaikge1xyXG4gICAgY2hhcnQuaGVpZ2h0ID0gY2hhcnRPcHRpb25zLmNoYXJ0LmhlaWdodDtcclxuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xyXG4gIH1cclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/P1xyXG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIHNldE9wdGlvbnMoSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zKSk7XHJcblxyXG4gIEhpZ2hjaGFydHNbb3B0aW9ucy5leHBvcnQuY29uc3RyIHx8ICdjaGFydCddKFxyXG4gICAgJ2NvbnRhaW5lcicsXHJcbiAgICBmaW5hbE9wdGlvbnMsXHJcbiAgICBmaW5hbENhbGxiYWNrXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgc2V0T3B0aW9ucyB3YXMgdXNlZCBpbiB0aGUgY3VzdG9tQ29kZSlcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBmcyBmcm9tICdmcyc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuY29uc3QgdGVtcGxhdGUgPSBmcy5yZWFkRmlsZVN5bmMoXHJcbiAgX19kaXJuYW1lICsgJy8uLi90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsXHJcbiAgJ3V0ZjgnXHJcbik7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpLmRlYnVnO1xyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogJ3NoZWxsJyxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWcpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgICdbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHRoZSBjb250ZW50IG9mIHRoZSBwYWdlLidcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdHJpZ2dlckV4cG9ydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZ1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzb3VyY2UuZGlzcG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFVzZSByZXNvdXJjZXNcclxuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gICAgaWYgKHJlc291cmNlcykge1xyXG4gICAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUkFTVEVSSVpBVElPTlxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKHBhZ2UsIHZpZXdwb3J0SGVpZ2h0LCB2aWV3cG9ydFdpZHRoLCAnYmFzZTY0Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY2xvc2UgYXMgYnJvd3NlckNsb3NlLFxyXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxyXG4gIG5ld1BhZ2UgYXMgYnJvd3Nlck5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gICAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHRoZSBwYWdlZXJyb3IgbGlzdGVuZXJcclxuICAgIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxyXG4gICAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCB7IG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZSh3b3JrZXJIYW5kbGUucGFnZSwgb3RoZXIuaGFyZFJlc2V0UGFnZSk7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXHJcbiAgICovXHJcbiAgZGVzdHJveTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgbG9nKDMsIGBbcG9vbF0gRGVzdHJveWluZyBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gV2UgZG9uJ3QgcmVhbGx5IG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgYXdhaXQgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIoY29uZmlnLnB1cHBldGVlckFyZ3MpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxyXG4gICk7XHJcblxyXG4gIGlmIChwb29sKSB7XHJcbiAgICByZXR1cm4gbG9nKFxyXG4gICAgICA0LFxyXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xyXG4gICAgcG9vbENvbmZpZy5taW5Xb3JrZXJzID0gcG9vbENvbmZpZy5tYXhXb3JrZXJzO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXHJcbiAgICAgIC4uLmZhY3RvcnksXHJcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcclxuICAgICAgbWF4OiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogS2lsbHMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGJyb3dzZXJDbG9zZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxyXG4gICAgICAgICAgOiAnJykgK1xyXG4gICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKiovXHJcblxyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXHJcbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXHJcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XHJcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRJbnRlcnZhbCxcclxuICBjbGVhckFsbEludGVydmFsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgIHJlcy5zZW5kKHtcclxuICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICB1cHRpbWU6XHJcbiAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXHJcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXHJcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxyXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXHJcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XHJcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICpcclxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLnBvc3QoXHJcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXHJcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInJlY3Vyc2l2ZVByb3BzIiwib2JqZWN0VG9VcGRhdGUiLCJuZXN0ZWROYW1lcyIsInNoaWZ0IiwiYXNzaWduIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsImNhY2hlJDEiLCJuZXdWZXJzaW9uIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsInRyaWdnZXJFeHBvcnQiLCJjaGFydE9wdGlvbnMiLCJkaXNwbGF5RXJyb3JzIiwiX2Rpc3BsYXlFcnJvcnMiLCJtZXJnZSIsInNldE9wdGlvbnMiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsIkZ1bmN0aW9uIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwicHJvcCIsInRlbXBsYXRlIiwiZnMiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJ3YWl0VW50aWwiLCJldmFsdWF0ZSIsImJvZHkiLCJpbm5lckhUTUwiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCIkZXZhbCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwiZXJyb3JNZXNzYWdlIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImV2ZW50SWQiLCJpbml0aWFsUmVzb3VyY2VzIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwiY29ubmVjdGVkIiwiYnJvd3NlckNsb3NlIiwicG9zdFdvcmsiLCJnZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwicGF5bG9hZCIsInJlcXVlc3RJZCIsIndvcmtTdGFydCIsImV4cG9ydENvdW50ZXIiLCJyZXN1bHQiLCJleHBvcnRUaW1lIiwiZ2V0UG9vbEluZm9KU09OIiwibnVtRnJlZSIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJwZW5kaW5nIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJpbnB1dCIsIkpTRE9NIiwiRE9NUHVyaWZ5Iiwic2FuaXRpemUiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsInBhcmFtcyIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiNnRCQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsV0FFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwrQkFDQSx1QkFDQSw2R0FDQSx5QkFDQSxvQ0FDQSxvQkFDQSwwQkFDQSw4Q0FDQSwyQkFDQSwwQkFDQSw2QkFDQSxtQ0FDQSx3Q0FDQSxtQ0FDQSwyQkFDQSxrQ0FDQSx1QkFDQSxpQkFDQSx5QkFDQSw4QkFDQSxvQkFDQSwyQkFDQSxlQUNBLDZCQUNBLGlCQUNBLGFBQ0EsZUFDQSxzQkFDQSxjQUNBLHlCQUNBLG9CQUNBLHVCQUVGQyxLQUFNLFdBQ05DLFlBQWEsMENBR2pCQyxXQUFZLENBQ1ZDLFFBQVMsQ0FDUEosTUFBTyxTQUNQQyxLQUFNLFNBQ05J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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(R[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(R[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),o.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=H;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=H;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([i[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else o=W(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const i=V(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:Z(i[e],n,r);var o;return i};function ee(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?ee(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in N&&void 0!==N[o.envLink]&&(o.value=N[o.envLink]))}))}function te(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:te(i);return t}function re(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=re(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function ie(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class oe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const o=await ie(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,i,o)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,i,o,n)=>{let s;const a=o.host,l=o.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...i.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,i,l),ne.hcVersion=se(ne),e.writeFileSync(o,ne.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:i,server:o}=r,n=t.join(F,i.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||i.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=i,u=n.length+c.length+p.length;r.version!==i.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(i,o.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ne.activeManifest=o,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(i,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:i,merge:o,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=o(!1,{},i()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=o(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;n(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const u=i();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await we(e),e}async function we(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Ee=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Te=(e,t,r,i)=>e.evaluate(me,t,r,i);var Se=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{U(4,"[export] Determining export path.");const a=o.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Te(r,{chart:{height:a.height,width:a.width}},o,l):(i.chart.height=a.height,i.chart.width=a.width,await Te(r,i,o,l));const p=o.customLogic.resources;if(p){const i=[];if(p.js&&i.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");i.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of i)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}i.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):o.customLogic.allowFileResources&&s.push({path:t.join(Ee,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,i=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:i}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new oe("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new oe(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:i})))(r,h,d,"base64")}return await s(r),f}catch(e){return await s(r),e}};let xe=!1;const Re={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const Oe={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new oe("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}const{debug:i}=Q();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(Le.workLimit&&++e.workCount>Le.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},_e=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,i={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(i)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new oe("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),xe)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{xe=new c.Pool({...Oe,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),xe.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await we(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),xe.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{xe.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),xe){for(const e of xe.used)xe.release(e.resource);xe.destroyed||(await xe.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ie=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Re.exportAttempts,Le.benchmarking&&Ae(),!xe)throw new oe("Work received, but pool has not been started.");const i=J();try{U(4,"[pool] Acquiring a worker handle."),r=await xe.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${i()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${i()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await Se(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),xe.release(r);const a=(new Date).getTime()-o;return Re.timeSpent+=a,Re.spentAverage=Re.timeSpent/++Re.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Re.droppedExports,r&&xe.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ce=()=>({min:xe.min,max:xe.max,all:xe.numFree()+xe.numUsed(),available:xe.numFree(),used:xe.numUsed(),pending:xe.numPendingAcquires()});function Ae(){const{min:e,max:t,all:r,available:i,used:o,pending:n}=Ce();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${i}.`),U(5,`[pool] The number of acquired resources: ${o}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Ne=Ce,Pe=()=>Re;let He=!1;const $e=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Ge(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(i.payload.svg),i,r);return++Re.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Ge(i.export.instr.trim(),i,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(i.customLogic?.allowCodeExecution)?De(i,r):"string"==typeof o.instr?Ge(o.instr.trim(),i,r):je(i,o.instr||o.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),i=W(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},je=async(t,r,i,o)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ue(t)};try{return i(!1,await Ie(n.strInj||r||o,t))}catch(e){return i(e)}},De=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=B(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,je(e,!1,t)}catch(r){return t(new oe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ge=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),je(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return je(t,i,r)}catch(e){return z(i)?De(t,r):r(new oe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Fe=[],Me=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},qe=(e,t,r,i)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,i(e)},We=(e,t,r,i)=>{const{statusCode:o,status:n,message:s,stack:a}=e,l=o||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Ve=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=v({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),U(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Be extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Xe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Ke=[],Je=[],Ye=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:s,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,s,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},Qe=async(e,t,r)=>{try{const r=J(),o=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++ze;let l=M(s.type);if(!s||"object"==typeof(i=s)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ye(Ke,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await $e(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,Ye(Je,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Xe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const Ze=JSON.parse(e.readFileSync(t.join(F,"package.json"))),et=new Date,tt=[];function rt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Pe(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;tt.push(t),tt.length>30&&tt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=Pe(),i=tt.length,o=tt.reduce(((e,t)=>e+t),0)/tt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ne(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const it=new Map,ot=m();ot.disable("x-powered-by"),ot.use(g());const nt=f.memoryStorage(),st=f({storage:nt,limits:{fieldSize:52428800}});ot.use(m.json({limit:52428800})),ot.use(m.urlencoded({extended:!0,limit:52428800})),ot.use(st.none());const at=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(ot);at(e),e.listen(r.port,r.host),it.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},ot);at(e),e.listen(r.ssl.port,r.host),it.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ve(ot,r.rateLimiting),ot.use(m.static(t.posix.join(F,"public"))),rt(ot),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(ot),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(ot),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Be("No new version supplied.",400);try{await ue(o)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(ot),(e=>{e.use(qe),e.use(We)})(ot)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},ct=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of it)t.close((()=>{it.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>it,enableRateLimiting:e=>Ve(ot,e),getExpress:()=>m,getApp:()=>ot,use:(e,...t)=>{ot.use(e,...t)},get:(e,...t)=>{ot.get(e,...t)},post:(e,...t)=>{ot.post(e,...t)}};const ut=async e=>{await Promise.allSettled([Me(),ct(),ke()]),process.exit(e)};var ht={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ut(1)}))),await ce(e),await _e({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await $e(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push($e({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:$e,initPool:_e,killPool:ke,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let i=!1;for(let o=0;o(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=z(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ut,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=re(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:X};module.exports=ht; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBkZWJ1ZyBtb2RlIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2hlYWRsZXNzJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZHVtcGlvJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZHVtcGlvLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Nsb3dNbycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGVidWdnaW5nUG9ydC52YWx1ZVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXHJcbiAgJ29wdGlvbnMnLFxyXG4gICdnbG9iYWxPcHRpb25zJyxcclxuICAndGhlbWVPcHRpb25zJyxcclxuICAncmVzb3VyY2VzJyxcclxuICAncGF5bG9hZCdcclxuXTtcclxuXHJcbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGNyZWF0ZXMgYSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzIGZyb20gYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XHJcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xyXG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcclxuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn07XHJcblxyXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xyXG4iLCIvKipcclxuICogQGZpbGVvdmVydmlld1xyXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJ1xyXG4gKiBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZCB0byBiZSB1c2VkXHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi4gV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHlcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXHJcbiAqXHJcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuXHJcbiAqIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lclxyXG4gKiBmb3IgZWFjaCBvZiB0aGUgb3B0aW9ucy5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgc2NyaXB0c05hbWVzIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gT2JqZWN0IHdpdGggY3VzdG9tIHZhbGlkYXRvcnMgYW5kIHRyYW5zZm9ybWVycywgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4vLyBpbiB0aGUgQ29uZmlnIG9iamVjdFxyXG5jb25zdCB2ID0ge1xyXG4gIC8vIFNwbGl0cyBzdHJpbmcgdmFsdWUgaW50byBlbGVtZW50cyBpbiBhbiBhcnJheSwgdHJpbXMgZXZlcnkgZWxlbWVudCwgY2hlY2tzXHJcbiAgLy8gaWYgYW4gYXJyYXkgaXMgY29ycmVjdCwgaWYgaXQgaXMgZW1wdHksIGFuZCBpZiBpdCBpcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBhcnJheTogKGZpbHRlckFycmF5KSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWVcclxuICAgICAgICAgIC5zcGxpdCgnLCcpXHJcbiAgICAgICAgICAubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKVxyXG4gICAgICAgICAgLmZpbHRlcigodmFsdWUpID0+IGZpbHRlckFycmF5LmluY2x1ZGVzKHZhbHVlKSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlLmxlbmd0aCA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBvbmx5IHRydWUsIGZhbHNlIGFuZCBjb3JyZWN0bHkgcGFyc2UgdGhlIHZhbHVlIHRvIGJvb2xlYW5cclxuICAvLyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIGJvb2xlYW46ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA9PT0gJ3RydWUnIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwYXNzZWQgdmFsdWVzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBlbnVtOiAodmFsdWVzKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbLi4udmFsdWVzLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gVHJpbXMgdGhlIHN0cmluZyB2YWx1ZSBhbmQgY2hlY2tzIGlmIGl0IGlzIGVtcHR5IG9yIGNvbnRhaW5zIHN0cmluZ2lmaWVkXHJcbiAgLy8gdmFsdWVzIHN1Y2ggYXMgZmFsc2UsIHVuZGVmaW5lZCwgbnVsbCwgTmFOLCBpZiBpdCBkb2VzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIHN0cmluZzogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nXS5pbmNsdWRlcyh2YWx1ZSkgfHxcclxuICAgICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHN0cmluZyBjb250YWlucyBmb3JiaWRkZW4gdmFsdWVzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcG9zaXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgcG9zaXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID4gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgbm9uLW5lZ2F0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWVcclxuICAvLyB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIG5vbk5lZ2F0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpXHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgQ29uZmlnID0gei5vYmplY3Qoe1xyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcclxuICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5jb3JlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5tb2R1bGVzKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHYuc3RyaW5nKCksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX1RZUEU6IHYuZW51bShbJ2pwZWcnLCAncG5nJywgJ3BkZicsICdzdmcnXSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdi5lbnVtKFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10pLFxyXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1dJRFRIOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdi5ib29sZWFuKCksXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUFJPWFlfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gc2VydmVyIHNzbFxyXG4gIFNFUlZFUl9TU0xfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gcG9vbFxyXG4gIFBPT0xfTUlOX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGxvZ2dlclxyXG4gIExPR0dJTkdfTEVWRUw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlID09PSAnJyB8fFxyXG4gICAgICAgICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA8PSA1KSxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBMT0dHSU5HX0xFVkVMLiBXZSBvbmx5IGFjY2VwdCB2YWx1ZXMgZnJvbSAwIHRvIDUgYXMgbG9nZ2luZyBsZXZlbHMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcbiAgTE9HR0lOR19GSUxFOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfREVTVDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJlcy50ZXh0ID0gZGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIHNvdXJjZVBhdGhcclxuKSA9PiB7XHJcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XHJcbiAgY29uc3QgaGNWZXJzaW9uID0gdmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIXZlcnNpb24gPyAnJyA6IGAke3ZlcnNpb259L2A7XHJcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259JHtjfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2NkblVSTH0ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcclxuICAgICAgICAgIChpKSA9PiBgJHtjZG5VUkx9c3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgcHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PiB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xyXG4gICAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG4gIH1cclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBoaWdoY2hhcnRzLCBzZXJ2ZXIgfSA9IG9wdGlvbnM7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xyXG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0cztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKiBDcmVhdGUgdGhlIGFjdHVhbCBjaGFydCAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD8/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XHJcbiAgICAvLyBPdmVycmlkZSB1c2VyT3B0aW9ucyB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcclxuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcclxuICAgICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgfSxcclxuICAgICAgcGxvdE9wdGlvbnM6IHtcclxuICAgICAgICBzZXJpZXM6IHtcclxuICAgICAgICAgIGxhYmVsOiB7XHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdXNlck9wdGlvbnMgd2hlbiBmb3JFeHBvcnQgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEdldCB0aGUgdXNlciBvcHRpb25zXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5zdHJJbmp9YCkoKVxyXG4gICAgOiBjaGFydE9wdGlvbnM7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxyXG4gIC8vIHNldE9wdGlvbnMgZnVuY3Rpb24gYW5kIHVzZXIgb3B0aW9ucyB0byBjcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zKSxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgeyBjaGFydCB9XHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IG9wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2tcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcclxuICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgc2V0T3B0aW9ucyhKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpKTtcclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGZzIGZyb20gJ2ZzJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgX19kaXJuYW1lID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5jb25zdCB0ZW1wbGF0ZSA9IGZzLnJlYWRGaWxlU3luYyhcclxuICBfX2Rpcm5hbWUgKyAnLy4uL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJyxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbmxldCBicm93c2VyO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW5cclxuICogY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJyk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IHB1cHBldGVlckFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgUHVwcGV0ZWVyIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbWF4IHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXJcclxuICogaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXIgcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGUocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCB0aGUgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnIH0gPSBnZXRPcHRpb25zKCkuZGVidWc7XHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiAnc2hlbGwnLFxyXG4gICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1ZylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdHJ1ZSBhZnRlciB0aGUgYnJvd3NlclxyXG4gKiBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2UoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25ubmVjdGVkXHJcbiAgaWYgKGJyb3dzZXI/LmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBwYWdlXHJcbiAgY29uc3QgcGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuXHJcbiAgcmV0dXJuIHBhZ2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGhhcmRSZXNldCAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXHJcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvICdhYm91dDpibGFuaycgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxyXG4gKiBzdHJ1Y3R1cmUuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBMb2dzIHRocm93biBlcnJvciBpZiBjbGVhcmluZyB0aGUgcGFnZSBjb250ZW50IGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwYWdlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xyXG4gIHRyeSB7XHJcbiAgICBpZiAoIXBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcclxuICAgICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxyXG4gICAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgICdbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHRoZSBjb250ZW50IG9mIHRoZSBwYWdlLidcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdHJpZ2dlckV4cG9ydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZ1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzb3VyY2UuZGlzcG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFVzZSByZXNvdXJjZXNcclxuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gICAgaWYgKHJlc291cmNlcykge1xyXG4gICAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUkFTVEVSSVpBVElPTlxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKHBhZ2UsIHZpZXdwb3J0SGVpZ2h0LCB2aWV3cG9ydFdpZHRoLCAnYmFzZTY0Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY2xvc2UgYXMgYnJvd3NlckNsb3NlLFxyXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxyXG4gIG5ld1BhZ2UgYXMgYnJvd3Nlck5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gICAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHRoZSBwYWdlZXJyb3IgbGlzdGVuZXJcclxuICAgIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxyXG4gICAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgYnJvd3NlckNsb3NlKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFydCAtIFRoZSBjaGFydCBkYXRhIG9yIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGV4cG9ydCByZXN1bHRhbmRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IElmIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcclxuICAgIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1dvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcclxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIFRPRE86IElmIHRoZSBleHBvcnQgZmFpbGVkIGJlY2F1c2UgcHVwcGV0ZWVyIHRpbWVkIG91dCwgd2UgbmVlZCB0byBmb3JjZSBraWxsIHRoZSB3b3JrZXIgc28gd2UgZ2V0IGEgbmV3IHBhZ2UuIFRoYXQgbmVlZHMgdG8gYmUgaGFuZGxlZCBiZXR0ZXIgdGhhbiB0aGlzIGhhY2suXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gYXdhaXQgYnJvd3Nlck5ld1BhZ2UoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICsgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcblxyXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxyXG4gICAgLy8gaW4gdHVybiBpcyB1c2VkIGJ5IHRoZSAvaGVhbHRoIHJvdXRlLlxyXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcbiAgICBzdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9IG1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3N0YXRzLmRyb3BwZWRFeHBvcnRzO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbcG9vbF0gSW4gcG9vbC5wb3N0V29yazogJHtlcnJvci5tZXNzYWdlfWApLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8bnVsbH0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sID0gKCkgPT4gcG9vbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcclxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxyXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkIHJlc291cmNlczogJHthbGx9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYXZhaWxhYmxlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgYWNxdWlyZWQ6ICR7cGVuZGluZ30uYCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcclxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgKTtcclxuXHJcbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICA6IGluZm8ucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGNoYXJ0IGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGNhbGN1bGF0ZWQgaGVpZ2h0LCB3aWR0aCxcclxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpbmRDaGFydFNpemUgPSAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcclxuXHJcbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxyXG4gIGxldCBzY2FsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uc2NhbGUgfHxcclxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0U2NhbGUgfHxcclxuICAgIDE7XHJcblxyXG4gIC8vIHRoZSBzY2FsZSBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjEgYW5kIGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xyXG5cclxuICAvLyB3ZSB3YW50IHRvIHJvdW5kIHRoZSBudW1iZXJzIGxpa2UgMC4yMzIzNCAtPiAwLjIzXHJcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XHJcblxyXG4gIC8vIEZpbmQgY2hhcnQgc2l6ZSBhbmQgc2NhbGVcclxuICBjb25zdCBzaXplID0ge1xyXG4gICAgaGVpZ2h0OlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgICA0MDAsXHJcbiAgICB3aWR0aDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcclxuICAgICAgNjAwLFxyXG4gICAgc2NhbGVcclxuICB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBweCBhbmQgJVxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG4gIHJldHVybiBzaXplO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXHJcbiAqIGNvbXBsZXRpb24gb3IgZXJyb3IuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlZC5cclxuICovXHJcbmNvbnN0IGRvRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMsIGNoYXJ0SnNvbiwgZW5kQ2FsbGJhY2ssIHN2ZykgPT4ge1xyXG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkID1cclxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcclxuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgIDogYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zID0gb3B0aW9ucy5jdXN0b21Mb2dpYyA9IHt9O1xyXG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XHJcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBQcm9jZXNzIHJlc291cmNlc1xyXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcclxuICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVzb3VyY2VzLFxyXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcclxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXHJcbiAgLy8gcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC4gUHJpb3JpdGl6ZWQgc2hvdWxkIGJlIHRoZSBzY29wZWRcclxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxyXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcclxuICAgICAgLy8gdGhlc2Ugc2V0dGluZ3MuXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYFxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cclxuICBpZiAoY2hhcnRKc29uKSB7XHJcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcuZW5hYmxlZCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBleHBvcnRPcHRpb25zLmNvbnN0ciB8fCAnY2hhcnQnO1xyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGdsb2JhbCBhbmQgdGhlbWUgb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMgJiYgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnJHtvcHRpb25zTmFtZX0nIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgdHJ5IHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjdXN0b21Db2RlJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xyXG4gIGlmIChcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcclxuICApIHtcclxuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxyXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xyXG4gICAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTaXplIHNlYXJjaFxyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAuLi5maW5kQ2hhcnRTaXplKG9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHRyeSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcclxuICAgICAgZXhwb3J0T3B0aW9ucy5zdHJJbmogfHwgY2hhcnRKc29uIHx8IHN2ZyxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgKTtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhmYWxzZSwgcmVzdWx0KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXHJcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxyXG4gKiBlbnN1cmluZyBhIGNsZWFuIGFuZCBmb3JtYXR0ZWQgaW5wdXQuIFRoZSByZXN1bHRpbmcgc3RyaW5nIGlzIHNhdmVkIGFzXHJcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcclxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXHJcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxyXG4gKiB0byBiZSBpbmplY3RlZC5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZFxyXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cclxuICovXHJcbmNvbnN0IGRvU3RyYWlnaHRJbmplY3QgPSAob3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICB0cnkge1xyXG4gICAgbGV0IHN0ckluajtcclxuICAgIGxldCBpbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gVHJ5IHRvIHN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHN0ckluaiA9IGluc3RyLnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcnKS50cmltKCk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xyXG4gICAgaWYgKHN0cklualtzdHJJbmoubGVuZ3RoIC0gMV0gPT09ICc7Jykge1xyXG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxyXG4gKiBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZy5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcclxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0QXNTdHJpbmcgPSAoc3RyaW5nVG9FeHBvcnQsIG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XHJcblxyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDBcclxuICApIHtcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2ssIHN0cmluZ1RvRXhwb3J0KTtcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cclxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XHJcblxyXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxyXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHZhbHVlIG9mIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcclxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZmluZENoYXJ0U2l6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqKi9cclxuXHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cclxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcclxuICogb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD4uLi48L3NjcmlwdD4gdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcclxuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZEludGVydmFsLFxyXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcclxuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIGlmICghYXBwKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cclxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xyXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXl9IC0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0U2VydmVycyA9ICgpID0+IGFjdGl2ZVNlcnZlcnM7XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRFeHByZXNzID0gKCkgPT4gZXhwcmVzcztcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpKTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IGNhY2hlLnVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgY2xlYXJBbGxJbnRlcnZhbHMgfSBmcm9tICcuL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBDbGVhbiB1cCBmdW5jdGlvbiB0byB0cmlnZ2VyIGJlZm9yZSBlbmRpbmcgcHJvY2VzcyBmb3IgdGhlIGdyYWNlZnVsIHNodXRkb3duLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBwcm9jZXNzLmV4aXQoKSBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaHV0ZG93bkNsZWFuVXAgPSBhc3luYyAoZXhpdENvZGUpID0+IHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbEludGVydmFscygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2UsIGlmIGV4aXN0c1xyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gUG9vbFxyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJwcm9tcHRzQ29uZmlnIiwibmFtZSIsIm1lc3NhZ2UiLCJpbml0aWFsIiwiam9pbiIsInNlcGFyYXRvciIsImluc3RydWN0aW9ucyIsImNob2ljZXMiLCJoaW50IiwibWluIiwibWF4Iiwicm91bmQiLCJhYnNvbHV0ZVByb3BzIiwibmVzdGVkQXJncyIsImNyZWF0ZU5lc3RlZEFyZ3MiLCJvYmoiLCJwcm9wQ2hhaW4iLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImsiLCJpbmNsdWRlcyIsImVudHJ5Iiwic3Vic3RyaW5nIiwidW5kZWZpbmVkIiwiZG90ZW52IiwiY29uZmlnIiwidiIsImZpbHRlckFycmF5IiwieiIsInN0cmluZyIsInRyYW5zZm9ybSIsInNwbGl0IiwibWFwIiwidHJpbSIsImZpbHRlciIsImxlbmd0aCIsImVudW0iLCJ2YWx1ZXMiLCJyZWZpbmUiLCJpc05hTiIsInBhcnNlRmxvYXQiLCJlbnZzIiwib2JqZWN0IiwiSElHSENIQVJUU19WRVJTSU9OIiwidGVzdCIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsInN0YXJ0c1dpdGgiLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfREVGQVVMVF9IRUlHSFQiLCJFWFBPUlRfREVGQVVMVF9XSURUSCIsIkVYUE9SVF9ERUZBVUxUX1NDQUxFIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX0JFTkNITUFSS0lORyIsIlNFUlZFUl9QUk9YWV9IT1NUIiwiU0VSVkVSX1BST1hZX1BPUlQiLCJTRVJWRVJfUFJPWFlfVElNRU9VVCIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4iLCJTRVJWRVJfU1NMX0VOQUJMRSIsIlNFUlZFUl9TU0xfRk9SQ0UiLCJTRVJWRVJfU1NMX1BPUlQiLCJTRVJWRVJfU1NMX0NFUlRfUEFUSCIsIlBPT0xfTUlOX1dPUktFUlMiLCJQT09MX01BWF9XT1JLRVJTIiwiUE9PTF9XT1JLX0xJTUlUIiwiUE9PTF9BQ1FVSVJFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9USU1FT1VUIiwiUE9PTF9ERVNUUk9ZX1RJTUVPVVQiLCJQT09MX0lETEVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMIiwiUE9PTF9SRUFQRVJfSU5URVJWQUwiLCJQT09MX0JFTkNITUFSS0lORyIsIkxPR0dJTkdfTEVWRUwiLCJMT0dHSU5HX0ZJTEUiLCJMT0dHSU5HX0RFU1QiLCJVSV9FTkFCTEUiLCJVSV9ST1VURSIsIk9USEVSX05PREVfRU5WIiwiT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMiLCJPVEhFUl9OT19MT0dPIiwiT1RIRVJfSEFSRF9SRVNFVF9QQUdFIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwicGFydGlhbCIsInBhcnNlIiwicHJvY2VzcyIsImVudiIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImVycm9yIiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwiRGF0ZSIsInRvU3RyaW5nIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIml0ZW0iLCJkYXRhIiwicGFyc2VkRGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwidGV4dCIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwicmVzcG9uc2UiLCJ1cGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwicHJveHlPcHRpb25zIiwic291cmNlUGF0aCIsInByb3h5QWdlbnQiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJmZXRjaFNjcmlwdHMiLCJjIiwibSIsIndyaXRlRmlsZVN5bmMiLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwibWFuaWZlc3RQYXRoIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlTWFwIiwibnVtYmVyT2ZNb2R1bGVzIiwic29tZSIsIm1vZHVsZU5hbWUiLCJuZXdNYW5pZmVzdCIsInNhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0Q2FjaGVQYXRoIiwiY2FjaGUkMSIsIm5ld1ZlcnNpb24iLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiRnVuY3Rpb24iLCJjaGFydCIsImFuaW1hdGlvbiIsInN0ckluaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50Iiwic2V0Q29udGVudCIsIndhaXRVbnRpbCIsImFkZFNjcmlwdFRhZyIsInBhdGgiLCJldmFsdWF0ZSIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsIngiLCJ5IiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsImVycm9yTWVzc2FnZSIsImlubmVySFRNTCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiY2xvc2UiLCJpbml0UG9vbCIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiY3JlYXRlQnJvd3NlciIsInBhcnNlSW50IiwiUG9vbCIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJicm93c2VyQ2xvc2UiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluZGV4IiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwiY29kZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicGFpckFyZ3VtZW50VmFsdWUiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlz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 diff --git a/dist/index.esm.js b/dist/index.esm.js index dc74d4cc..6458f6f7 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},N=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?N(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};N(_),u.config();const A=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:A(O.core),HIGHCHARTS_MODULE_SCRIPTS:A(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:A(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:G(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:G(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:G(),SERVER_RATE_LIMITING_WINDOW:G(),SERVER_RATE_LIMITING_DELAY:G(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:G(),POOL_MAX_WORKERS:G(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:G(),POOL_CREATE_TIMEOUT:G(),POOL_DESTROY_TIMEOUT:G(),POOL_IDLE_TIMEOUT:G(),POOL_CREATE_RETRY_INTERVAL:G(),POOL_REAPER_INTERVAL:G(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:G(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:D.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;s(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Oe(e),e}async function Le(e,t=!1){try{t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Oe(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}async function Oe(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const _e=g.fileURLToPath(new URL(".",import.meta.url)),ke=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var Ie=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await ke(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await ke(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(_e,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o})))(e,u,d,"base64")}return await s(e),f}catch(t){return await s(e),t}};let Ce=!1;const Ne={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Pe={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>{if(Ae.workLimit&&++e.workCount>Ae.workLimit)return W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1;try{const{other:t}=ie();return await Le(e.page,t.hardResetPage),!0}catch{return!1}},destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},He=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ce)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ce=new y({...Pe,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ce.on("release",(async e=>{await Le(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ce.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ce.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function $e(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ce){for(const e of Ce.used)Ce.release(e.resource);Ce.destroyed||(await Ce.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const Ue=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ne.exportAttempts,Ae.benchmarking&&De(),!Ce)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ce.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await Ie(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ce.release(r);const a=(new Date).getTime()-i;return Ne.timeSpent+=a,Ne.spentAverage=Ne.timeSpent/++Ne.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ne.droppedExports,r&&Ce.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ge=()=>({min:Ce.min,max:Ce.max,all:Ce.numFree()+Ce.numUsed(),available:Ce.numFree(),used:Ce.numUsed(),pending:Ce.numPendingAcquires()});function De(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ge();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var je=Ge,Me=()=>Ne;let Fe=!1;const We=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Xe(function(e){const t=new E("").window;return T(t).sanitize(e)}(r.payload.svg),r,t);return++Ne.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Xe(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?Be(r,t):"string"==typeof o.instr?Xe(o.instr.trim(),r,t):qe(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ve=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},qe=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Fe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await Ue(s.strInj||t||o,e))}catch(e){return r(e)}},Be=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,qe(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Xe=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),qe(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return qe(t,o,r)}catch(e){return ee(o)?Be(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Ke=[],Je=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Ke)clearInterval(e)},ze=(e,t,r,o)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},Ye=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Qe=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Ze extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const et={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let tt=0;const rt=[],ot=[],it=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},st=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++tt;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Ze("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Ze("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=it(rt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Fe,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Ze("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await We(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Ze(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,it(ot,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",et[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const nt=JSON.parse(i(l(X,"package.json"))),at=new Date,lt=[];function ct(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Me(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;lt.push(t),lt.length>30&<.shift()}),6e4),Ke.push(t),e.get("/health",((e,t)=>{const r=Me(),o=lt.length,i=lt.reduce(((e,t)=>e+t),0)/lt.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:at,uptime:Math.floor(((new Date).getTime()-at.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:je(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const pt=new Map,ht=x();ht.disable("x-powered-by"),ht.use(S());const ut=R.memoryStorage(),dt=R({storage:ut,limits:{fieldSize:52428800}});ht.use(x.json({limit:52428800})),ht.use(x.urlencoded({extended:!0,limit:52428800})),ht.use(dt.none());const gt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},mt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(ht);gt(t),t.listen(e.port,e.host),pt.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},ht);gt(o),o.listen(e.ssl.port,e.host),pt.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Qe(ht,e.rateLimiting),ht.use(x.static(c.join(X,"public"))),ct(ht),(e=>{e.post("/",st),e.post("/:filename",st)})(ht),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(ht),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Ze("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Ze("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Ze("No new version supplied.",400);try{await ve(i)}catch(e){throw new Ze(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(ht),(e=>{e.use(ze),e.use(Ye)})(ht)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},ft=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of pt)t.close((()=>{pt.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var vt={startServer:mt,closeServers:ft,getServers:()=>pt,enableRateLimiting:e=>Qe(ht,e),getExpress:()=>x,getApp:()=>ht,use:(e,...t)=>{ht.use(e,...t)},get:(e,...t)=>{ht.get(e,...t)},post:(e,...t)=>{ht.post(e,...t)}};const yt=async e=>{await Promise.allSettled([Je(),ft(),$e()]),process.exit(e)};var bt={server:vt,startServer:mt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Fe=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await yt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await yt(1)}))),await me(e),await He({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await We(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await $e()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(We({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await $e()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:We,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:yt,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{bt as default}; +import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},A=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?A(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};A(_),u.config();const N=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:N(O.core),HIGHCHARTS_MODULE_SCRIPTS:N(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:N(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:G(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:G(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:G(),SERVER_RATE_LIMITING_WINDOW:G(),SERVER_RATE_LIMITING_DELAY:G(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:G(),POOL_MAX_WORKERS:G(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:G(),POOL_CREATE_TIMEOUT:G(),POOL_DESTROY_TIMEOUT:G(),POOL_IDLE_TIMEOUT:G(),POOL_CREATE_RETRY_INTERVAL:G(),POOL_REAPER_INTERVAL:G(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:G(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:D.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;s(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Le(e),e}async function Le(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const Oe=g.fileURLToPath(new URL(".",import.meta.url)),_e=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var ke=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await _e(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await _e(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(Oe,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o})))(e,u,d,"base64")}return await s(e),f}catch(t){return await s(e),t}};let Ie=!1;const Ce={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Ne={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>!(Ae.workLimit&&++e.workCount>Ae.workLimit)||(W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1),destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Pe=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ie)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ie=new y({...Ne,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ie.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Le(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ie.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ie.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function He(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ie){for(const e of Ie.used)Ie.release(e.resource);Ie.destroyed||(await Ie.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const $e=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ce.exportAttempts,Ae.benchmarking&&Ge(),!Ie)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ie.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await ke(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ie.release(r);const a=(new Date).getTime()-i;return Ce.timeSpent+=a,Ce.spentAverage=Ce.timeSpent/++Ce.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ce.droppedExports,r&&Ie.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ue=()=>({min:Ie.min,max:Ie.max,all:Ie.numFree()+Ie.numUsed(),available:Ie.numFree(),used:Ie.numUsed(),pending:Ie.numPendingAcquires()});function Ge(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ue();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var De=Ue,je=()=>Ce;let Me=!1;const Fe=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Be(function(e){const t=new E("").window;return T(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++Ce.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Be(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?qe(r,t):"string"==typeof o.instr?Be(o.instr.trim(),r,t):Ve(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},We=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ve=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Me;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...We(e)};try{return r(!1,await $e(s.strInj||t||o,e))}catch(e){return r(e)}},qe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ve(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Be=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),Ve(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ve(t,o,r)}catch(e){return ee(o)?qe(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Xe=[],Ke=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Xe)clearInterval(e)},Je=(e,t,r,o)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},ze=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ye=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Qe extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let et=0;const tt=[],rt=[],ot=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},it=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++et;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Qe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Qe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=ot(tt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Me,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Qe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Qe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ot(rt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const st=JSON.parse(i(l(X,"package.json"))),nt=new Date,at=[];function lt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;at.push(t),at.length>30&&at.shift()}),6e4),Xe.push(t),e.get("/health",((e,t)=>{const r=je(),o=at.length,i=at.reduce(((e,t)=>e+t),0)/at.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:nt,uptime:Math.floor(((new Date).getTime()-nt.getTime())/1e3/60)+" minutes",version:st.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:De(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ct=new Map,pt=x();pt.disable("x-powered-by"),pt.use(S());const ht=R.memoryStorage(),ut=R({storage:ht,limits:{fieldSize:52428800}});pt.use(x.json({limit:52428800})),pt.use(x.urlencoded({extended:!0,limit:52428800})),pt.use(ut.none());const dt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},gt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(pt);dt(t),t.listen(e.port,e.host),ct.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},pt);dt(o),o.listen(e.ssl.port,e.host),ct.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(pt,e.rateLimiting),pt.use(x.static(c.join(X,"public"))),lt(pt),(e=>{e.post("/",it),e.post("/:filename",it)})(pt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(pt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Qe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Qe("No new version supplied.",400);try{await ve(i)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(pt),(e=>{e.use(Je),e.use(ze)})(pt)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},mt=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of ct)t.close((()=>{ct.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var ft={startServer:gt,closeServers:mt,getServers:()=>ct,enableRateLimiting:e=>Ye(pt,e),getExpress:()=>x,getApp:()=>pt,use:(e,...t)=>{pt.use(e,...t)},get:(e,...t)=>{pt.get(e,...t)},post:(e,...t)=>{pt.post(e,...t)}};const vt=async e=>{await Promise.allSettled([Ke(),mt(),He()]),process.exit(e)};var yt={server:ft,startServer:gt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Me=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await vt(1)}))),await me(e),await Pe({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Fe(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await He()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Fe({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await He()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,initPool:Pe,killPool:He,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:vt,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{yt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 84e5b396..cba6ec54 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/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/** Called when initing the page */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/** Create the actual chart */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful??\r\n window.isRenderComplete = false;\r\n\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n setOptions(JSON.parse(options.export.globalOptions));\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (page, height, width, encoding) => {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n try {\r\n const { other } = getOptions();\r\n await clearPage(workerHandle.page, other.hardResetPage);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input);\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","setContent","addScriptTag","path","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,6GACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/** Called when initing the page */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/** Create the actual chart */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful??\r\n window.isRenderComplete = false;\r\n\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n setOptions(JSON.parse(options.export.globalOptions));\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (page, height, width, encoding) => {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","setContent","waitUntil","addScriptTag","path","evaluate","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","innerHTML","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file diff --git a/lib/browser.js b/lib/browser.js index af18427c..2533caa7 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -180,18 +180,20 @@ export async function newPage() { */ export async function clearPage(page, hardReset = false) { try { - if (hardReset) { - // Navigate to about:blank - await page.goto('about:blank', { waitUntil: 'domcontentloaded' }); - - // Set the content and and scripts again - await setPageContent(page); - } else { - // Clear body content - await page.evaluate(() => { - document.body.innerHTML = - '
'; - }); + if (!page.isClosed()) { + if (hardReset) { + // Navigate to about:blank + await page.goto('about:blank', { waitUntil: 'domcontentloaded' }); + + // Set the content and and scripts again + await setPageContent(page); + } else { + // Clear body content + await page.evaluate(() => { + document.body.innerHTML = + '
'; + }); + } } } catch (error) { logWithStack( diff --git a/lib/index.js b/lib/index.js index d398cc5d..5bea8b96 100644 --- a/lib/index.js +++ b/lib/index.js @@ -29,7 +29,7 @@ import { setLogLevel, enableFileLogging } from './logger.js'; -import { initPool } from './pool.js'; +import { initPool, killPool } from './pool.js'; import { shutdownCleanUp } from './resource_release.js'; import server, { startServer } from './server/server.js'; import { printLogo, printUsage } from './utils.js'; @@ -122,9 +122,9 @@ export default { batchExport, startExport, - // Other - setOptions, - shutdownCleanUp, + // Pool + initPool, + killPool, // Logs log, @@ -132,6 +132,10 @@ export default { setLogLevel, enableFileLogging, + // Other + setOptions, + shutdownCleanUp, + // Utils mapToNewConfig, manualConfig, diff --git a/lib/pool.js b/lib/pool.js index 887ef779..dc20a83f 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -131,15 +131,7 @@ const factory = { ); return false; } - - // Clear page - try { - const { other } = getOptions(); - await clearPage(workerHandle.page, other.hardResetPage); - return true; - } catch { - return false; - } + return true; }, /** diff --git a/lib/sanitize.js b/lib/sanitize.js index aca402ad..42ffa5bc 100644 --- a/lib/sanitize.js +++ b/lib/sanitize.js @@ -31,7 +31,7 @@ import DOMPurify from 'dompurify'; export function sanitize(input) { const window = new JSDOM('').window; const purify = DOMPurify(window); - return purify.sanitize(input); + return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] }); } export default sanitize; diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 83a49515..f14a6381 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -106,7 +106,7 @@ export const defaultConfig = { '--disable-dev-shm-usage', '--disable-domain-reliability', '--disable-extensions', - '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP', + '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP', '--disable-hang-monitor', '--disable-ipc-flooding-protection', '--disable-logging', diff --git a/package-lock.json b/package-lock.json index 34a2f52c..df9138b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.2", + "dompurify": "^3.1.3", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0", @@ -20,7 +20,7 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.8.0", + "puppeteer": "^22.8.1", "tarn": "^3.0.2", "uuid": "^9.0.1", "zod": "^3.23.8" @@ -1268,201 +1268,6 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", @@ -2960,9 +2765,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.2.tgz", - "integrity": "sha512-hLGGBI1tw5N8qTELr3blKjAML/LY4ANxksbS612UiJyDfyf/2D092Pvm+S7pmeTGJRqvlJkFzBoHBQKgQlOQVg==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.3.tgz", + "integrity": "sha512-5sOWYSNPaxz6o2MUPvtyxTTqR4D3L77pr5rUQoWgD5ROQtVIZQgJkXbo1DLlK3vj11YGw5+LnF4SYti4gZmwng==" }, "node_modules/dotenv": { "version": "16.4.5", @@ -2981,9 +2786,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.761", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.761.tgz", - "integrity": "sha512-PIbxpiJGx6Bb8dQaonNc6CGTRlVntdLg/2nMa1YhnrwYOORY9a3ZgGN0UQYE6lAcj/lkyduJN7BPt/JiY+jAQQ==", + "version": "1.4.762", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.762.tgz", + "integrity": "sha512-rrFvGweLxPwwSwJOjIopy3Vr+J3cIPtZzuc74bmlvmBIgQO3VYJDvVrlj94iKZ3ukXUH64Ex31hSfRTLqvjYJQ==", "dev": true }, "node_modules/emittery": { @@ -3880,20 +3685,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -6743,15 +6534,15 @@ } }, "node_modules/puppeteer": { - "version": "22.8.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.0.tgz", - "integrity": "sha512-Z616wyTr0d7KpxmfcBG22rAkzuo/xzHJ3ycpu4KiJ3dZNHn/C1CpqcCwPlpiIIsmPojTAfWjo6EMR7M+AaC0Ww==", + "version": "22.8.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.1.tgz", + "integrity": "sha512-CFgPSKV+iydjO/8/hJVj251Hqp2PLcIa70j6H7sYqkwM8YJ+D3CA74Ufuj+yKtvDIntQPB/nLw4EHrHPcHOPjw==", "hasInstallScript": true, "dependencies": { "@puppeteer/browsers": "2.2.3", "cosmiconfig": "9.0.0", "devtools-protocol": "0.0.1273771", - "puppeteer-core": "22.8.0" + "puppeteer-core": "22.8.1" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -6761,9 +6552,9 @@ } }, "node_modules/puppeteer-core": { - "version": "22.8.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.0.tgz", - "integrity": "sha512-S5bWx3g/fNuyFxjZX9TkZMN07CEH47+9Zm6IiTl1QfqI9pnVaShbwrD9kRe5vmz/XPp/jLGhhxRUj1sY4wObnA==", + "version": "22.8.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.1.tgz", + "integrity": "sha512-m1F6ZSTw1xrJ6xD4B+HonkSNVQmMrRMaqca/ivRcZYJ6jqzOnfEh3QgO9HpNPj6heiAZ2+4IPAU3jdZaTIDnSA==", "dependencies": { "@puppeteer/browsers": "2.2.3", "chromium-bidi": "0.5.19", diff --git a/package.json b/package.json index 34520e78..d6c62e8a 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,8 @@ "install": "node ./install.js", "prestart": "rm -rf tmp || del -rf tmp /Q && node ./node_modules/puppeteer/install.mjs", "start": "node ./bin/cli.js --enableServer 1 --logLevel 2", - "start:debug": "node --inspect-brk=9229 ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", - "start:debug-browser": "node ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", - "start:debug-node": "node --inspect-brk=9229 ./bin/cli.js --enableServer 1 --logLevel 4", "start:dev": "nodemon ./bin/cli.js --enableServer 1 --logLevel 4", + "start:debug": "node --inspect-brk=9229 ./bin/cli.js --enableDebug 1 --enableServer 1 --logLevel 4", "lint": "eslint ./ --fix", "cli-tests": "node ./tests/cli/cli_test_runner.js", "cli-tests-single": "node ./tests/cli/cli_test_runner_single.js", @@ -56,7 +54,7 @@ "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.2", + "dompurify": "^3.1.3", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0", @@ -64,7 +62,7 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.8.0", + "puppeteer": "^22.8.1", "tarn": "^3.0.2", "uuid": "^9.0.1", "zod": "^3.23.8" diff --git a/tests/cli/scenarios/constr.json b/tests/cli/scenarios/constr.json index b1099d90..f59d1eb3 100644 --- a/tests/cli/scenarios/constr.json +++ b/tests/cli/scenarios/constr.json @@ -1,4 +1,4 @@ { - "instr": "{\"title\":{\"text\":\"Stock chart constr\"},\"xAxis\":{\"categories\":[\"Jan\",\"Feb\",\"Mar\",\"Apr\"]},\"series\":[{\"type\":\"column\",\"data\":[5,6,7,8]},{\"type\":\"line\",\"data\":[1,2,3,4]}]}", + "instr": "{\"title\":{\"text\":\"Stock chart constr\"},\"series\":[{\"type\":\"column\",\"data\":[5,6,7,8]},{\"type\":\"line\",\"data\":[1,2,3,4]}]}", "constr": "stockChart" } diff --git a/tests/http/scenarios/constr.json b/tests/http/scenarios/constr.json index fe6755f0..f2b84289 100644 --- a/tests/http/scenarios/constr.json +++ b/tests/http/scenarios/constr.json @@ -3,9 +3,6 @@ "title": { "text": "The 'constr' option is set to use stockChart" }, - "xAxis": { - "categories": ["Jan", "Feb", "Mar", "Apr"] - }, "series": [ { "type": "column", From df5f1503c8d78cc81971cb092d78aec751efc22a Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Mon, 13 May 2024 19:16:07 +0200 Subject: [PATCH 5/7] Added docs for debug mode along with further corrections. --- README.md | 32 +++++++++++++++++++++++++++++++- dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/export.js | 36 ++++++++++++++++++++++++++++-------- lib/highcharts.js | 20 +++++++++++++++----- lib/index.js | 8 ++++---- lib/schemas/config.js | 33 +++++++++++++++++++-------------- 8 files changed, 101 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 94df5d8d..5c072a9e 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,15 @@ The format, along with its default values, is as follows (using the recommended "listenToProcessExits": true, "noLogo": false, "hardResetPage": false + }, + "debug": { + "enable": false, + "headless": true, + "devtools": false, + "listenToConsole": false, + "dumpio": false, + "slowMo": 0, + "debuggingPort": 9222 } } ``` @@ -353,6 +362,15 @@ These variables are set in your environment and take precedence over options fro - `OTHER_NO_LOGO`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `OTHER_HARD_RESET_PAGE`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). +### Debugging Config +- `DEBUG_ENABLE`: Enables or disables debug mode for the underlying browser (defaults to `false`). +- `DEBUG_HEADLESS`: Controls the mode in which the browser is launched when in the debug mode (defaults to `true`). +- `DEBUG_DEVTOOLS`: Decides whether to enable DevTools when the browser is in a headful state (defaults to `false`). +- `DEBUG_LISTEN_TO_CONSOLE`: Decides whether to enable a listener for console messages sent from the browser (defaults to `false`). +- `DEBUG_DUMPIO`: Redirects browser process stdout and stderr to process.stdout and process.stderr (defaults to `false`). +- `DEBUG_SLOW_MO`: Slows down Puppeteer operations by the specified number of milliseconds (defaults to `0`). +- `DEBUG_DEBUGGING_PORT`: Specifies the debugging port (defaults to `9222`). + ## Command Line Arguments To supply command line arguments, add them as flags when running the application: @@ -417,6 +435,13 @@ _Available options:_ - `--listenToProcessExits`: Decides whether or not to attach process.exit handlers (defaults to `true`). - `--noLogo`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `--hardResetPage`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). +- `--enableDebug`: Enables or disables debug mode for the underlying browser (defaults to `false`). +- `--headless`: Controls the mode in which the browser is launched when in the debug mode (defaults to `true`). +- `--devtools`: Decides whether to enable DevTools when the browser is in a headful state (defaults to `false`). +- `--listenToConsole`: Decides whether to enable a listener for console messages sent from the browser (defaults to `false`). +- `--dumpio`: Redirects browser process stdout and stderr to process.stdout and process.stderr (defaults to `false`). +- `--slowMo`: Slows down Puppeteer operations by the specified number of milliseconds (defaults to `0`). +- `--debuggingPort`: Specifies the debugging port (defaults to `9222`). # HTTP Server @@ -555,7 +580,7 @@ This package supports both CommonJS and ES modules. **highcharts-export-server module** - `server`: The server instance which offers the following functions: - - `async startServer(serverConfig)`: The same as `startServer` describe below. + - `async startServer(serverConfig)`: The same as `startServer` described below. - `closeServers()`: Closes all servers associated with Express app instance. @@ -596,6 +621,11 @@ This package supports both CommonJS and ES modules. - `{Object} settings`: The settings object containing export configuration. - `{function} endCallback`: The callback function to be invoked upon finalizing work or upon error occurance of the exporting process. +- `async initPool(config)`: Initializes the export pool with the provided configuration, creating a browser instance and setting up worker resources. + - `{Object} config`: Configuration options for the export pool along with custom puppeteer arguments for the puppeteer.launch function. + +- `async killPool()`: Kills all workers in the pool, destroys the pool, and closes the browser instance. + - `setOptions(userOptions, args)`: Initializes and sets the general options for the server instace, keeping the principle of the options load priority. It accepts optional userOptions and args from the CLI. - `{Object} userOptions`: User-provided options for customization. - `{Array} args`: Command-line arguments for additional configuration (CLI usage). diff --git a/dist/index.cjs b/dist/index.cjs index 2f726829..4ea67951 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(R[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(R[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),o.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=H;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=H;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([i[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else o=W(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const i=V(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:Z(i[e],n,r);var o;return i};function ee(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?ee(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in N&&void 0!==N[o.envLink]&&(o.value=N[o.envLink]))}))}function te(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:te(i);return t}function re(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=re(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function ie(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class oe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const o=await ie(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,i,o)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,i,o,n)=>{let s;const a=o.host,l=o.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...i.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,i,l),ne.hcVersion=se(ne),e.writeFileSync(o,ne.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:i,server:o}=r,n=t.join(F,i.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||i.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=i,u=n.length+c.length+p.length;r.version!==i.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(i,o.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ne.activeManifest=o,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(i,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:i,merge:o,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=o(!1,{},i()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=o(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;n(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const u=i();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await we(e),e}async function we(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Ee=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Te=(e,t,r,i)=>e.evaluate(me,t,r,i);var Se=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{U(4,"[export] Determining export path.");const a=o.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Te(r,{chart:{height:a.height,width:a.width}},o,l):(i.chart.height=a.height,i.chart.width=a.width,await Te(r,i,o,l));const p=o.customLogic.resources;if(p){const i=[];if(p.js&&i.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");i.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of i)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}i.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):o.customLogic.allowFileResources&&s.push({path:t.join(Ee,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,i=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:i}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new oe("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new oe(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:i})))(r,h,d,"base64")}return await s(r),f}catch(e){return await s(r),e}};let xe=!1;const Re={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const Oe={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new oe("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}const{debug:i}=Q();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(Le.workLimit&&++e.workCount>Le.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},_e=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,i={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(i)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new oe("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),xe)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{xe=new c.Pool({...Oe,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),xe.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await we(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),xe.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{xe.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),xe){for(const e of xe.used)xe.release(e.resource);xe.destroyed||(await xe.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ie=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Re.exportAttempts,Le.benchmarking&&Ae(),!xe)throw new oe("Work received, but pool has not been started.");const i=J();try{U(4,"[pool] Acquiring a worker handle."),r=await xe.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${i()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${i()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let o=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await Se(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),xe.release(r);const a=(new Date).getTime()-o;return Re.timeSpent+=a,Re.spentAverage=Re.timeSpent/++Re.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Re.droppedExports,r&&xe.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ce=()=>({min:xe.min,max:xe.max,all:xe.numFree()+xe.numUsed(),available:xe.numFree(),used:xe.numUsed(),pending:xe.numPendingAcquires()});function Ae(){const{min:e,max:t,all:r,available:i,used:o,pending:n}=Ce();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${i}.`),U(5,`[pool] The number of acquired resources: ${o}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Ne=Ce,Pe=()=>Re;let He=!1;const $e=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Ge(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(i.payload.svg),i,r);return++Re.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),Ge(i.export.instr.trim(),i,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(i.customLogic?.allowCodeExecution)?De(i,r):"string"==typeof o.instr?Ge(o.instr.trim(),i,r):je(i,o.instr||o.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),i=W(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},je=async(t,r,i,o)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ue(t)};try{return i(!1,await Ie(n.strInj||r||o,t))}catch(e){return i(e)}},De=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=B(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,je(e,!1,t)}catch(r){return t(new oe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ge=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),je(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return je(t,i,r)}catch(e){return z(i)?De(t,r):r(new oe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Fe=[],Me=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},qe=(e,t,r,i)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,i(e)},We=(e,t,r,i)=>{const{statusCode:o,status:n,message:s,stack:a}=e,l=o||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Ve=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=v({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),U(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Be extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Xe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Ke=[],Je=[],Ye=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:s,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,s,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},Qe=async(e,t,r)=>{try{const r=J(),o=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++ze;let l=M(s.type);if(!s||"object"==typeof(i=s)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ye(Ke,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await $e(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,Ye(Je,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Xe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const Ze=JSON.parse(e.readFileSync(t.join(F,"package.json"))),et=new Date,tt=[];function rt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Pe(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;tt.push(t),tt.length>30&&tt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=Pe(),i=tt.length,o=tt.reduce(((e,t)=>e+t),0)/tt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ne(),period:i,movingAverage:o,message:`Last ${i} minutes had a success rate of ${o.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const it=new Map,ot=m();ot.disable("x-powered-by"),ot.use(g());const nt=f.memoryStorage(),st=f({storage:nt,limits:{fieldSize:52428800}});ot.use(m.json({limit:52428800})),ot.use(m.urlencoded({extended:!0,limit:52428800})),ot.use(st.none());const at=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(ot);at(e),e.listen(r.port,r.host),it.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let i,o;try{i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=l.createServer({key:i,cert:o},ot);at(e),e.listen(r.ssl.port,r.host),it.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ve(ot,r.rateLimiting),ot.use(m.static(t.posix.join(F,"public"))),rt(ot),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(ot),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(ot),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Be("No new version supplied.",400);try{await ue(o)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(ot),(e=>{e.use(qe),e.use(We)})(ot)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},ct=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of it)t.close((()=>{it.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>it,enableRateLimiting:e=>Ve(ot,e),getExpress:()=>m,getApp:()=>ot,use:(e,...t)=>{ot.use(e,...t)},get:(e,...t)=>{ot.get(e,...t)},post:(e,...t)=>{ot.post(e,...t)}};const ut=async e=>{await Promise.allSettled([Me(),ct(),ke()]),process.exit(e)};var ht={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ut(1)}))),await ce(e),await _e({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await $e(t,(async(t,r)=>{if(t)throw t;const{outfile:i,type:o}=r.options.export;e.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let i of t.export.batch.split(";"))i=i.split("="),2===i.length&&r.push($e({...t,export:{...t.export,infile:i[0],outfile:i[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:$e,initPool:_e,killPool:ke,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const i=t[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(e.readFileSync(i))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let i=!1;for(let o=0;o(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=z(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ut,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const o=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return i({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(o,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await i(a,{onSubmit:async(i,o)=>{if("moduleScripts"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=re(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const i=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${i}\n`.bold)},printUsage:X};module.exports=ht; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnLidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBkZWJ1ZyBtb2RlIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2hlYWRsZXNzJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZHVtcGlvJyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZHVtcGlvLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Nsb3dNbycsXHJcbiAgICAgIG1lc3NhZ2U6ICcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGVidWdnaW5nUG9ydC52YWx1ZVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXHJcbiAgJ29wdGlvbnMnLFxyXG4gICdnbG9iYWxPcHRpb25zJyxcclxuICAndGhlbWVPcHRpb25zJyxcclxuICAncmVzb3VyY2VzJyxcclxuICAncGF5bG9hZCdcclxuXTtcclxuXHJcbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGNyZWF0ZXMgYSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzIGZyb20gYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XHJcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xyXG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcclxuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn07XHJcblxyXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xyXG4iLCIvKipcclxuICogQGZpbGVvdmVydmlld1xyXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJ1xyXG4gKiBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZCB0byBiZSB1c2VkXHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi4gV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHlcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXHJcbiAqXHJcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuXHJcbiAqIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lclxyXG4gKiBmb3IgZWFjaCBvZiB0aGUgb3B0aW9ucy5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgc2NyaXB0c05hbWVzIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gT2JqZWN0IHdpdGggY3VzdG9tIHZhbGlkYXRvcnMgYW5kIHRyYW5zZm9ybWVycywgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4vLyBpbiB0aGUgQ29uZmlnIG9iamVjdFxyXG5jb25zdCB2ID0ge1xyXG4gIC8vIFNwbGl0cyBzdHJpbmcgdmFsdWUgaW50byBlbGVtZW50cyBpbiBhbiBhcnJheSwgdHJpbXMgZXZlcnkgZWxlbWVudCwgY2hlY2tzXHJcbiAgLy8gaWYgYW4gYXJyYXkgaXMgY29ycmVjdCwgaWYgaXQgaXMgZW1wdHksIGFuZCBpZiBpdCBpcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBhcnJheTogKGZpbHRlckFycmF5KSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWVcclxuICAgICAgICAgIC5zcGxpdCgnLCcpXHJcbiAgICAgICAgICAubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKVxyXG4gICAgICAgICAgLmZpbHRlcigodmFsdWUpID0+IGZpbHRlckFycmF5LmluY2x1ZGVzKHZhbHVlKSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlLmxlbmd0aCA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBvbmx5IHRydWUsIGZhbHNlIGFuZCBjb3JyZWN0bHkgcGFyc2UgdGhlIHZhbHVlIHRvIGJvb2xlYW5cclxuICAvLyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIGJvb2xlYW46ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA9PT0gJ3RydWUnIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwYXNzZWQgdmFsdWVzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBlbnVtOiAodmFsdWVzKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbLi4udmFsdWVzLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gVHJpbXMgdGhlIHN0cmluZyB2YWx1ZSBhbmQgY2hlY2tzIGlmIGl0IGlzIGVtcHR5IG9yIGNvbnRhaW5zIHN0cmluZ2lmaWVkXHJcbiAgLy8gdmFsdWVzIHN1Y2ggYXMgZmFsc2UsIHVuZGVmaW5lZCwgbnVsbCwgTmFOLCBpZiBpdCBkb2VzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIHN0cmluZzogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nXS5pbmNsdWRlcyh2YWx1ZSkgfHxcclxuICAgICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHN0cmluZyBjb250YWlucyBmb3JiaWRkZW4gdmFsdWVzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcG9zaXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgcG9zaXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID4gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgbm9uLW5lZ2F0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWVcclxuICAvLyB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIG5vbk5lZ2F0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpXHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgQ29uZmlnID0gei5vYmplY3Qoe1xyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcclxuICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5jb3JlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5tb2R1bGVzKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHYuc3RyaW5nKCksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX1RZUEU6IHYuZW51bShbJ2pwZWcnLCAncG5nJywgJ3BkZicsICdzdmcnXSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdi5lbnVtKFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10pLFxyXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1dJRFRIOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdi5ib29sZWFuKCksXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUFJPWFlfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gc2VydmVyIHNzbFxyXG4gIFNFUlZFUl9TU0xfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gcG9vbFxyXG4gIFBPT0xfTUlOX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGxvZ2dlclxyXG4gIExPR0dJTkdfTEVWRUw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlID09PSAnJyB8fFxyXG4gICAgICAgICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA8PSA1KSxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBMT0dHSU5HX0xFVkVMLiBXZSBvbmx5IGFjY2VwdCB2YWx1ZXMgZnJvbSAwIHRvIDUgYXMgbG9nZ2luZyBsZXZlbHMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcbiAgTE9HR0lOR19GSUxFOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfREVTVDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJlcy50ZXh0ID0gZGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgcHJveHlPcHRpb25zLFxyXG4gIHNvdXJjZVBhdGhcclxuKSA9PiB7XHJcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XHJcbiAgY29uc3QgaGNWZXJzaW9uID0gdmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIXZlcnNpb24gPyAnJyA6IGAke3ZlcnNpb259L2A7XHJcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259JHtjfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2NkblVSTH0ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcclxuICAgICAgICAgIChpKSA9PiBgJHtjZG5VUkx9c3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgcHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PiB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xyXG4gICAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG4gIH1cclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBoaWdoY2hhcnRzLCBzZXJ2ZXIgfSA9IG9wdGlvbnM7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xyXG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0cztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShoaWdoY2hhcnRzLCBzZXJ2ZXIucHJveHksIHNvdXJjZVBhdGgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKiBDcmVhdGUgdGhlIGFjdHVhbCBjaGFydCAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD8/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XHJcbiAgICAvLyBPdmVycmlkZSB1c2VyT3B0aW9ucyB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcclxuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcclxuICAgICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgfSxcclxuICAgICAgcGxvdE9wdGlvbnM6IHtcclxuICAgICAgICBzZXJpZXM6IHtcclxuICAgICAgICAgIGxhYmVsOiB7XHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdXNlck9wdGlvbnMgd2hlbiBmb3JFeHBvcnQgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEdldCB0aGUgdXNlciBvcHRpb25zXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5zdHJJbmp9YCkoKVxyXG4gICAgOiBjaGFydE9wdGlvbnM7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxyXG4gIC8vIHNldE9wdGlvbnMgZnVuY3Rpb24gYW5kIHVzZXIgb3B0aW9ucyB0byBjcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zKSxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgeyBjaGFydCB9XHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IG9wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2tcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcclxuICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgc2V0T3B0aW9ucyhKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpKTtcclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGZzIGZyb20gJ2ZzJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgX19kaXJuYW1lID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5jb25zdCB0ZW1wbGF0ZSA9IGZzLnJlYWRGaWxlU3luYyhcclxuICBfX2Rpcm5hbWUgKyAnLy4uL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJyxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbmxldCBicm93c2VyO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW5cclxuICogY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJyk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IHB1cHBldGVlckFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgUHVwcGV0ZWVyIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbWF4IHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXJcclxuICogaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXIgcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGUocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCB0aGUgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnIH0gPSBnZXRPcHRpb25zKCkuZGVidWc7XHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiAnc2hlbGwnLFxyXG4gICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1ZylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdHJ1ZSBhZnRlciB0aGUgYnJvd3NlclxyXG4gKiBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2UoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25ubmVjdGVkXHJcbiAgaWYgKGJyb3dzZXI/LmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBwYWdlXHJcbiAgY29uc3QgcGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuXHJcbiAgcmV0dXJuIHBhZ2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGhhcmRSZXNldCAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXHJcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvICdhYm91dDpibGFuaycgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxyXG4gKiBzdHJ1Y3R1cmUuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBMb2dzIHRocm93biBlcnJvciBpZiBjbGVhcmluZyB0aGUgcGFnZSBjb250ZW50IGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwYWdlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xyXG4gIHRyeSB7XHJcbiAgICBpZiAoIXBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcclxuICAgICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxyXG4gICAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgICdbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHRoZSBjb250ZW50IG9mIHRoZSBwYWdlLidcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdHJpZ2dlckV4cG9ydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZ1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgICAgYXdhaXQgcmVzb3VyY2UuZGlzcG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFVzZSByZXNvdXJjZXNcclxuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gICAgaWYgKHJlc291cmNlcykge1xyXG4gICAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAgIC8vIExvYWQgQ1NTXHJcbiAgICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fYmFzZWRpciwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUkFTVEVSSVpBVElPTlxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKHBhZ2UsIHZpZXdwb3J0SGVpZ2h0LCB2aWV3cG9ydFdpZHRoLCAnYmFzZTY0Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY2xvc2UgYXMgYnJvd3NlckNsb3NlLFxyXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxyXG4gIG5ld1BhZ2UgYXMgYnJvd3Nlck5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcbiAgICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gICAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHRoZSBwYWdlZXJyb3IgbGlzdGVuZXJcclxuICAgIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxyXG4gICAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgYnJvd3NlckNsb3NlKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFydCAtIFRoZSBjaGFydCBkYXRhIG9yIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGV4cG9ydCByZXN1bHRhbmRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IElmIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcclxuICAgIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1dvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcclxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIFRPRE86IElmIHRoZSBleHBvcnQgZmFpbGVkIGJlY2F1c2UgcHVwcGV0ZWVyIHRpbWVkIG91dCwgd2UgbmVlZCB0byBmb3JjZSBraWxsIHRoZSB3b3JrZXIgc28gd2UgZ2V0IGEgbmV3IHBhZ2UuIFRoYXQgbmVlZHMgdG8gYmUgaGFuZGxlZCBiZXR0ZXIgdGhhbiB0aGlzIGhhY2suXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gYXdhaXQgYnJvd3Nlck5ld1BhZ2UoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICsgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcblxyXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxyXG4gICAgLy8gaW4gdHVybiBpcyB1c2VkIGJ5IHRoZSAvaGVhbHRoIHJvdXRlLlxyXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcbiAgICBzdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9IG1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3N0YXRzLmRyb3BwZWRFeHBvcnRzO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbcG9vbF0gSW4gcG9vbC5wb3N0V29yazogJHtlcnJvci5tZXNzYWdlfWApLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8bnVsbH0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sID0gKCkgPT4gcG9vbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcclxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxyXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkIHJlc291cmNlczogJHthbGx9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYXZhaWxhYmxlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgYWNxdWlyZWQ6ICR7cGVuZGluZ30uYCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcclxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgKTtcclxuXHJcbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICA6IGluZm8ucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGNoYXJ0IGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGNhbGN1bGF0ZWQgaGVpZ2h0LCB3aWR0aCxcclxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpbmRDaGFydFNpemUgPSAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcclxuXHJcbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxyXG4gIGxldCBzY2FsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uc2NhbGUgfHxcclxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0U2NhbGUgfHxcclxuICAgIDE7XHJcblxyXG4gIC8vIHRoZSBzY2FsZSBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjEgYW5kIGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xyXG5cclxuICAvLyB3ZSB3YW50IHRvIHJvdW5kIHRoZSBudW1iZXJzIGxpa2UgMC4yMzIzNCAtPiAwLjIzXHJcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XHJcblxyXG4gIC8vIEZpbmQgY2hhcnQgc2l6ZSBhbmQgc2NhbGVcclxuICBjb25zdCBzaXplID0ge1xyXG4gICAgaGVpZ2h0OlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgICA0MDAsXHJcbiAgICB3aWR0aDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XHJcbiAgICAgIGV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LndpZHRoIHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcclxuICAgICAgNjAwLFxyXG4gICAgc2NhbGVcclxuICB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBweCBhbmQgJVxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG4gIHJldHVybiBzaXplO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXHJcbiAqIGNvbXBsZXRpb24gb3IgZXJyb3IuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlZC5cclxuICovXHJcbmNvbnN0IGRvRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMsIGNoYXJ0SnNvbiwgZW5kQ2FsbGJhY2ssIHN2ZykgPT4ge1xyXG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkID1cclxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcclxuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgIDogYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zID0gb3B0aW9ucy5jdXN0b21Mb2dpYyA9IHt9O1xyXG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XHJcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBQcm9jZXNzIHJlc291cmNlc1xyXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcclxuICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVzb3VyY2VzLFxyXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcclxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXHJcbiAgLy8gcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC4gUHJpb3JpdGl6ZWQgc2hvdWxkIGJlIHRoZSBzY29wZWRcclxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxyXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcclxuICAgICAgLy8gdGhlc2Ugc2V0dGluZ3MuXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYFxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cclxuICBpZiAoY2hhcnRKc29uKSB7XHJcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcuZW5hYmxlZCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBleHBvcnRPcHRpb25zLmNvbnN0ciB8fCAnY2hhcnQnO1xyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGdsb2JhbCBhbmQgdGhlbWUgb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMgJiYgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnJHtvcHRpb25zTmFtZX0nIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgdHJ5IHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjdXN0b21Db2RlJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xyXG4gIGlmIChcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcclxuICApIHtcclxuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxyXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xyXG4gICAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTaXplIHNlYXJjaFxyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAuLi5maW5kQ2hhcnRTaXplKG9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHRyeSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcclxuICAgICAgZXhwb3J0T3B0aW9ucy5zdHJJbmogfHwgY2hhcnRKc29uIHx8IHN2ZyxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgKTtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhmYWxzZSwgcmVzdWx0KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXHJcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxyXG4gKiBlbnN1cmluZyBhIGNsZWFuIGFuZCBmb3JtYXR0ZWQgaW5wdXQuIFRoZSByZXN1bHRpbmcgc3RyaW5nIGlzIHNhdmVkIGFzXHJcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcclxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXHJcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxyXG4gKiB0byBiZSBpbmplY3RlZC5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZFxyXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cclxuICovXHJcbmNvbnN0IGRvU3RyYWlnaHRJbmplY3QgPSAob3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICB0cnkge1xyXG4gICAgbGV0IHN0ckluajtcclxuICAgIGxldCBpbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gVHJ5IHRvIHN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHN0ckluaiA9IGluc3RyLnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcnKS50cmltKCk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xyXG4gICAgaWYgKHN0cklualtzdHJJbmoubGVuZ3RoIC0gMV0gPT09ICc7Jykge1xyXG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxyXG4gKiBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZy5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcclxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0QXNTdHJpbmcgPSAoc3RyaW5nVG9FeHBvcnQsIG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XHJcblxyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDBcclxuICApIHtcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2ssIHN0cmluZ1RvRXhwb3J0KTtcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cclxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XHJcblxyXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxyXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHZhbHVlIG9mIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcclxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZmluZENoYXJ0U2l6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqKi9cclxuXHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cclxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcclxuICogb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD4uLi48L3NjcmlwdD4gdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcclxuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZEludGVydmFsLFxyXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcclxuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIGlmICghYXBwKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cclxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xyXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXl9IC0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0U2VydmVycyA9ICgpID0+IGFjdGl2ZVNlcnZlcnM7XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRFeHByZXNzID0gKCkgPT4gZXhwcmVzcztcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpKTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IGNhY2hlLnVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgY2xlYXJBbGxJbnRlcnZhbHMgfSBmcm9tICcuL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBDbGVhbiB1cCBmdW5jdGlvbiB0byB0cmlnZ2VyIGJlZm9yZSBlbmRpbmcgcHJvY2VzcyBmb3IgdGhlIGdyYWNlZnVsIHNodXRkb3duLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBwcm9jZXNzLmV4aXQoKSBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaHV0ZG93bkNsZWFuVXAgPSBhc3luYyAoZXhpdENvZGUpID0+IHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbEludGVydmFscygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2UsIGlmIGV4aXN0c1xyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gUG9vbFxyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJwcm9tcHRzQ29uZmlnIiwibmFtZSIsIm1lc3NhZ2UiLCJpbml0aWFsIiwiam9pbiIsInNlcGFyYXRvciIsImluc3RydWN0aW9ucyIsImNob2ljZXMiLCJoaW50IiwibWluIiwibWF4Iiwicm91bmQiLCJhYnNvbHV0ZVByb3BzIiwibmVzdGVkQXJncyIsImNyZWF0ZU5lc3RlZEFyZ3MiLCJvYmoiLCJwcm9wQ2hhaW4iLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImsiLCJpbmNsdWRlcyIsImVudHJ5Iiwic3Vic3RyaW5nIiwidW5kZWZpbmVkIiwiZG90ZW52IiwiY29uZmlnIiwidiIsImZpbHRlckFycmF5IiwieiIsInN0cmluZyIsInRyYW5zZm9ybSIsInNwbGl0IiwibWFwIiwidHJpbSIsImZpbHRlciIsImxlbmd0aCIsImVudW0iLCJ2YWx1ZXMiLCJyZWZpbmUiLCJpc05hTiIsInBhcnNlRmxvYXQiLCJlbnZzIiwib2JqZWN0IiwiSElHSENIQVJUU19WRVJTSU9OIiwidGVzdCIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsInN0YXJ0c1dpdGgiLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfREVGQVVMVF9IRUlHSFQiLCJFWFBPUlRfREVGQVVMVF9XSURUSCIsIkVYUE9SVF9ERUZBVUxUX1NDQUxFIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX0JFTkNITUFSS0lORyIsIlNFUlZFUl9QUk9YWV9IT1NUIiwiU0VSVkVSX1BST1hZX1BPUlQiLCJTRVJWRVJfUFJPWFlfVElNRU9VVCIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4iLCJTRVJWRVJfU1NMX0VOQUJMRSIsIlNFUlZFUl9TU0xfRk9SQ0UiLCJTRVJWRVJfU1NMX1BPUlQiLCJTRVJWRVJfU1NMX0NFUlRfUEFUSCIsIlBPT0xfTUlOX1dPUktFUlMiLCJQT09MX01BWF9XT1JLRVJTIiwiUE9PTF9XT1JLX0xJTUlUIiwiUE9PTF9BQ1FVSVJFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9USU1FT1VUIiwiUE9PTF9ERVNUUk9ZX1RJTUVPVVQiLCJQT09MX0lETEVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMIiwiUE9PTF9SRUFQRVJfSU5URVJWQUwiLCJQT09MX0JFTkNITUFSS0lORyIsIkxPR0dJTkdfTEVWRUwiLCJMT0dHSU5HX0ZJTEUiLCJMT0dHSU5HX0RFU1QiLCJVSV9FTkFCTEUiLCJVSV9ST1VURSIsIk9USEVSX05PREVfRU5WIiwiT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMiLCJPVEhFUl9OT19MT0dPIiwiT1RIRVJfSEFSRF9SRVNFVF9QQUdFIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwicGFydGlhbCIsInBhcnNlIiwicHJvY2VzcyIsImVudiIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImVycm9yIiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwiRGF0ZSIsInRvU3RyaW5nIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIml0ZW0iLCJkYXRhIiwicGFyc2VkRGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwidGV4dCIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwicmVzcG9uc2UiLCJ1cGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwicHJveHlPcHRpb25zIiwic291cmNlUGF0aCIsInByb3h5QWdlbnQiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJmZXRjaFNjcmlwdHMiLCJjIiwibSIsIndyaXRlRmlsZVN5bmMiLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwibWFuaWZlc3RQYXRoIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlTWFwIiwibnVtYmVyT2ZNb2R1bGVzIiwic29tZSIsIm1vZHVsZU5hbWUiLCJuZXdNYW5pZmVzdCIsInNhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0Q2FjaGVQYXRoIiwiY2FjaGUkMSIsIm5ld1ZlcnNpb24iLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiRnVuY3Rpb24iLCJjaGFydCIsImFuaW1hdGlvbiIsInN0ckluaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50Iiwic2V0Q29udGVudCIsIndhaXRVbnRpbCIsImFkZFNjcmlwdFRhZyIsInBhdGgiLCJldmFsdWF0ZSIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsIngiLCJ5IiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsImVycm9yTWVzc2FnZSIsImlubmVySFRNTCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiY2xvc2UiLCJpbml0UG9vbCIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiY3JlYXRlQnJvd3NlciIsInBhcnNlSW50IiwiUG9vbCIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJicm93c2VyQ2xvc2UiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluZGV4IiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwiY29kZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicGFpckFyZ3VtZW50VmFsdWUiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlz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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?L(o,`${t}.${r}`):(R[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(R[o.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),i.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=H;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=H;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([o[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=W(t),i&&!r&&delete i.files;for(const e in i)o.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):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const o=V(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Z(o[e],n,r);var i;return o};function ee(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?ee(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in N&&void 0!==N[i.envLink]&&(i.value=N[i.envLink]))}))}function te(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:te(o);return t}function re(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=re(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function oe(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ie extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const i=await oe(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ie(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,l=i.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new ie("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...o.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,l),ne.hcVersion=se(ne),e.writeFileSync(i,ne.sources),l}catch(e){throw new ie("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:o,server:i}=r,n=t.join(F,o.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(o,i.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=o,u=n.length+c.length+p.length;r.version!==o.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(o,i.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ne.activeManifest=i,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new ie("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await we(e),e}async function we(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Ee=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Te=(e,t,r,o)=>e.evaluate(me,t,r,o);var Se=async(r,o,i)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{U(4,"[export] Determining export path.");const a=i.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return o;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Te(r,{chart:{height:a.height,width:a.width}},i,l):(o.chart.height=a.height,o.chart.width=a.width,await Te(r,o,i,l));const p=i.customLogic.resources;if(p){const o=[];if(p.js&&o.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");o.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of o)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}o.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):i.customLogic.allowFileResources&&s.push({path:t.join(Ee,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new ie(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))])))(r,h,d,"base64",a.rasterizationTimeout)}return await s(r),f}catch(e){return await s(r),e}};let xe=!1;const Re={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const Oe={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new ie("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ie("Error encountered when creating a new page.").setError(e)}const{debug:o}=Q();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(Le.workLimit&&++e.workCount>Le.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},_e=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(o)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ie("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new ie("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),xe)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{xe=new c.Pool({...Oe,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),xe.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await we(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),xe.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{xe.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ie("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),xe){for(const e of xe.used)xe.release(e.resource);xe.destroyed||(await xe.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ie=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Re.exportAttempts,Le.benchmarking&&Ae(),!xe)throw new ie("Work received, but pool has not been started.");const o=J();try{U(4,"[pool] Acquiring a worker handle."),r=await xe.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new ie((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new ie("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await Se(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new ie((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),xe.release(r);const a=(new Date).getTime()-i;return Re.timeSpent+=a,Re.spentAverage=Re.timeSpent/++Re.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Re.droppedExports,r&&xe.release(r),new ie(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ce=()=>({min:xe.min,max:xe.max,all:xe.numFree()+xe.numUsed(),available:xe.numFree(),used:xe.numUsed(),pending:xe.numPendingAcquires()});function Ae(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Ce();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${o}.`),U(5,`[pool] The number of acquired resources: ${i}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Ne=Ce,Pe=()=>Re;let He=!1;const $e=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Ge(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++Re.exportFromSvgAttempts,e}catch(e){return r(new ie("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),Ge(o.export.instr.trim(),o,r)}catch(e){return r(new ie("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(o.customLogic?.allowCodeExecution)?De(o,r):"string"==typeof i.instr?Ge(i.instr.trim(),o,r):je(o,i.instr||i.options,r)}catch(e){return r(new ie("[chart] Error loading raw input.").setError(e))}return r(new ie("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),o=W(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},je=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new ie("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ue(t)};try{return o(!1,await Ie(n.strInj||r||i,t))}catch(e){return o(e)}},De=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=B(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,je(e,!1,t)}catch(r){return t(new ie(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ge=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),je(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return je(t,o,r)}catch(e){return z(o)?De(t,r):r(new ie("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Fe=[],Me=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},qe=(e,t,r,o)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,o(e)},We=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,l=i||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Ve=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),U(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Be extends ie{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Xe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Ke=[],Je=[],Ye=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Qe=async(e,t,r)=>{try{const r=J(),i=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++ze;let l=M(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ye(Ke,e,t,{id:a,uniqueId:i,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await $e(g,((o,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Ye(Je,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Xe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const Ze=JSON.parse(e.readFileSync(t.join(F,"package.json"))),et=new Date,tt=[];function rt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Pe(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;tt.push(t),tt.length>30&&tt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=Pe(),o=tt.length,i=tt.reduce(((e,t)=>e+t),0)/tt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ne(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ot=new Map,it=m();it.disable("x-powered-by"),it.use(g());const nt=f.memoryStorage(),st=f({storage:nt,limits:{fieldSize:52428800}});it.use(m.json({limit:52428800})),it.use(m.urlencoded({extended:!0,limit:52428800})),it.use(st.none());const at=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(it);at(e),e.listen(r.port,r.host),ot.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},it);at(e),e.listen(r.ssl.port,r.host),ot.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ve(it,r.rateLimiting),it.use(m.static(t.posix.join(F,"public"))),rt(it),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(it),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(it),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Be("No new version supplied.",400);try{await ue(i)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(it),(e=>{e.use(qe),e.use(We)})(it)}catch(e){throw new ie("[server] Could not configure and start the server.").setError(e)}},ct=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ot)t.close((()=>{ot.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>ot,enableRateLimiting:e=>Ve(it,e),getExpress:()=>m,getApp:()=>it,use:(e,...t)=>{it.use(e,...t)},get:(e,...t)=>{it.get(e,...t)},post:(e,...t)=>{it.post(e,...t)}};const ut=async e=>{await Promise.allSettled([Me(),ct(),ke()]),process.exit(e)};var ht={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ut(1)}))),await ce(e),await _e({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await $e(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push($e({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new ie("[chart] Error encountered during batch export.").setError(e)}},startExport:$e,initPool:_e,killPool:ke,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=z(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ut,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=re(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:X};module.exports=ht; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIGEgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgc2VudCBmcm9tIHRoZSBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYW5pbU9iamVjdC4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY2hhcnRPcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBIaWdoY2hhcnRzIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBkaXNwbGF5RXJyb3JzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciB0byBkaXNwbGF5IGVycm9ycy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0cmlnZ2VyRXhwb3J0KGNoYXJ0T3B0aW9ucywgb3B0aW9ucywgZGlzcGxheUVycm9ycykge1xyXG4gIC8vIERpc3BsYXkgZXJyb3JzIGZsYWcgdGFrZW4gZnJvbSBjaGFydCBvcHRpb25zIG5hZCBkZWJ1Z2dlciBtb2R1bGVcclxuICB3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkaXNwbGF5RXJyb3JzO1xyXG5cclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBtZXJnZSwgc2V0T3B0aW9ucywgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBzZXRPcHRpb25zIHVzYWdlcyBpbiBvcmRlciB0b1xyXG4gIC8vIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gVHJpZ2dlciBjdXN0b20gY29kZVxyXG4gIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpIHtcclxuICAgIG5ldyBGdW5jdGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKCk7XHJcbiAgfVxyXG5cclxuICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGNvbnN0IGNoYXJ0ID0ge1xyXG4gICAgYW5pbWF0aW9uOiBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFdoZW4gc3RyYWlnaHQgaW5qZWN0LCB0aGUgc2l6ZSBpcyBzZXQgdGhyb3VnaCBDU1Mgb25seVxyXG4gIGlmIChvcHRpb25zLmV4cG9ydC5zdHJJbmopIHtcclxuICAgIGNoYXJ0LmhlaWdodCA9IGNoYXJ0T3B0aW9ucy5jaGFydC5oZWlnaHQ7XHJcbiAgICBjaGFydC53aWR0aCA9IGNoYXJ0T3B0aW9ucy5jaGFydC53aWR0aDtcclxuICB9XHJcblxyXG4gIC8vIE5PVEU6IElzIHRoaXMgdXNlZCBmb3IgYW55dGhpbmcgdXNlZnVsP1xyXG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XHJcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XHJcbiAgICAvLyBPdmVycmlkZSB1c2VyT3B0aW9ucyB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcclxuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcclxuICAgICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgfSxcclxuICAgICAgcGxvdE9wdGlvbnM6IHtcclxuICAgICAgICBzZXJpZXM6IHtcclxuICAgICAgICAgIGxhYmVsOiB7XHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdXNlck9wdGlvbnMgd2hlbiBmb3JFeHBvcnQgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEdldCB0aGUgdXNlciBvcHRpb25zXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5zdHJJbmp9YCkoKVxyXG4gICAgOiBjaGFydE9wdGlvbnM7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxyXG4gIC8vIHNldE9wdGlvbnMgZnVuY3Rpb24gYW5kIHVzZXIgb3B0aW9ucyB0byBjcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zKSxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgeyBjaGFydCB9XHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IG9wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2tcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcclxuICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9ucyk7XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICBIaWdoY2hhcnRzW29wdGlvbnMuZXhwb3J0LmNvbnN0ciB8fCAnY2hhcnQnXShcclxuICAgICdjb250YWluZXInLFxyXG4gICAgZmluYWxPcHRpb25zLFxyXG4gICAgZmluYWxDYWxsYmFja1xyXG4gICk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIHNldE9wdGlvbnMgd2FzIHVzZWQgaW4gdGhlIGN1c3RvbUNvZGUpXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciB0aGUgcGFnZVxyXG5jb25zdCBfX2Rpcm5hbWUgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldCgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZShwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWcgfSA9IGdldE9wdGlvbnMoKS5kZWJ1ZztcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6ICdzaGVsbCcsXHJcbiAgICB1c2VyRGF0YURpcjogJy4vdG1wLycsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZSgpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIElmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdCBhdmFpbGFibGUsIHJldHVybnMgZmFsc2UuXHJcbiAqXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiBzZXRQYWdlQ29udGVudCgpLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XHJcbiAqIGF2YWlsYWJsZSwgb3IgYSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBuZXdseSBjcmVhdGVkIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmICghcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICAgIGF3YWl0IHBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLy4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IF9fYmFzZWRpciA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudCB3aXRoXHJcbiAqIHRoZSBpZCAnY2hhcnQtY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHgsIHksIHdpZHRoLCBhbmQgaGVpZ2h0IHByb3BlcnRpZXMuXHJcbiAqL1xyXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gaW1hZ2UgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBzY3JlZW5zaG90IGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gSW1hZ2UgZW5jb2RpbmcuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGltYWdlIGJ1ZmZlciBvciByZWplY3RpbmdcclxuICogd2l0aCBhbiBFeHBvcnRFcnJvciBmb3IgdGltZW91dC5cclxuICovXHJcbmNvbnN0IGNyZWF0ZUltYWdlID0gKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwLCByYXN0ZXJpemF0aW9uVGltZW91dCkgPT5cclxuICBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcclxuICAgICAgdHlwZSxcclxuICAgICAgZW5jb2RpbmcsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGNhcHR1cmVCZXlvbmRWaWV3cG9ydDogdHJ1ZSxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcblxyXG4gICAgICAvLyAjNDQ3LCAjNDYzIC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGVcclxuICAgICAgLy8gZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJ1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXHJcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxyXG4gICAgICApXHJcbiAgICApXHJcbiAgXSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlUERGID0gYXN5bmMgKFxyXG4gIHBhZ2UsXHJcbiAgaGVpZ2h0LFxyXG4gIHdpZHRoLFxyXG4gIGVuY29kaW5nLFxyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbikgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnBkZih7XHJcbiAgICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBlbmNvZGluZ1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXHJcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxyXG4gICAgICApXHJcbiAgICApXHJcbiAgXSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycykgPT5cclxuICBwYWdlLmV2YWx1YXRlKHRyaWdnZXJFeHBvcnQsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAqIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICovXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xyXG4gIGNvbnN0IGNsZWFySW5qZWN0ZWQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIGxldCBpc1NWRztcclxuICAgIGlmIChcclxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxyXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRy4nKTtcclxuXHJcbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBjaGFydDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICBkaXNwbGF5RXJyb3JzXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvbnN0IGluamVjdGVkSnMgPSBbXTtcclxuXHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaCh7XHJcbiAgICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgICAgaW5qZWN0ZWRKcy5wdXNoKFxyXG4gICAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xyXG5cclxuICAgICAgLy8gTG9hZCBDU1NcclxuICAgICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgICAgaWYgKHJlc291cmNlcy5jc3MpIHtcclxuICAgICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxyXG4gICAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcclxuICAgICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19iYXNlZGlyLCBjc3NJbXBvcnRQYXRoKVxyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xyXG4gICAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBzdmdFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcclxuICAgICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnXHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWVzIGNvcnJlY3RseSBzY2FsZWRcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0SGVpZ2h0ID0gc3ZnRWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG4gICAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XHJcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XHJcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcclxuICBleHBvcnRBdHRlbXB0czogMCxcclxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXHJcbiAgdGltZVNwZW50OiAwLFxyXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxyXG4gIHNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuICAgIC8vIFNldCB0aGUgY29uc29sZSBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdGhlIHBhZ2VlcnJvciBsaXN0ZW5lclxyXG4gICAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcclxuICAgICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICAgJyNjb250YWluZXInLFxyXG4gICAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgaWYgKHdpbmRvdy5fZGlzcGxheUVycm9ycykge1xyXG4gICAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LFxyXG4gICAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjogPC9oMT4ke2Vycm9yLnRvU3RyaW5nKCl9YFxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxyXG4gICAgICAgICAgOiAnJykgKyBgRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYWxsOiBwb29sLm51bUZyZWUoKSArIHBvb2wubnVtVXNlZCgpLFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgdXNlZDogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZzogcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHsgbWluLCBtYXgsIGFsbCwgYXZhaWxhYmxlLCB1c2VkLCBwZW5kaW5nIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgcmVzb3VyY2VzOiAke2FsbH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhdmFpbGFibGUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhY3F1aXJlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nfS5gKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbEluZm8sXHJcbiAgZ2V0UG9vbEluZm9KU09OLFxyXG4gIGdldFN0YXRzOiAoKSA9PiBzdGF0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGV4cG9ydEFzU3RyaW5nKFxyXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICApO1xyXG5cclxuICAgICAgKytzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHM7XHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcclxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgc2luZ2xlIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXHJcbiAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBvdXRmaWxlLCB0eXBlIH0gPSBpbmZvLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcclxuICAgICk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICoqL1xyXG5cclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxyXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxyXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7IEFERF9UQUdTOiBbJ2ZvcmVpZ25PYmplY3QnXSB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgc2FuaXRpemU7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbmNvbnN0IGludGVydmFsSWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiBhIHNldEludGVydmFsIHRvIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBhZGRJbnRlcnZhbCA9IChpZCkgPT4ge1xyXG4gIGludGVydmFsSWRzLnB1c2goaWQpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYnkgaWRzIGdhdGhlcmVkIGluIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhckFsbEludGVydmFscyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIGludGVydmFsSWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkSW50ZXJ2YWwsXHJcbiAgY2xlYXJBbGxJbnRlcnZhbHNcclxufTtcclxuIiwiaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBhZGRJbnRlcnZhbCB9IGZyb20gJy4uLy4uL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XHJcblxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwOyAvLyByZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDsgLy8gMzAgbWludXRlc1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIHN1Y2Nlc3NSYXRlc1xyXG4gKiBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgY29uc3Qgc3VtID0gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xyXG4gIHJldHVybiBzdW0gLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGdhdGhlcnNcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U3VjY2Vzc1JhdGUgPSAoKSA9PlxyXG4gIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xyXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgaWYgKCFhcHApIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxyXG4gIGFkZEludGVydmFsKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgIGxvZyg0LCAnW2hlYWx0aC5qc10gR0VUIC9oZWFsdGggWzIwMF0gLSByZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICByZXMuc2VuZCh7XHJcbiAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgdXB0aW1lOlxyXG4gICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxyXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxyXG4gICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzLFxyXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcclxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxyXG4gICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDAsXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgIHBlcmlvZCxcclxuICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgbWVzc2FnZTogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgIC8vIFNWRy9KU09OIGF0dGVtcHRzXHJcbiAgICAgIHN2Z0V4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgIGpzb25FeHBvcnRBdHRlbXB0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAtIHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0c1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tICcuL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXHJcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbmFwcC51c2UoY29ycygpKTtcclxuXHJcbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcclxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgc3RvcmFnZSxcclxuICBsaW1pdHM6IHtcclxuICAgIGZpZWxkU2l6ZTogNTAgKiAxMDI0ICogMTAyNFxyXG4gIH1cclxufSk7XHJcblxyXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcbmFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuXHJcbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG5hcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi4gVGhlIGBzZXJ2ZXJDb25maWdgXHJcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXHJcbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNlcnZlciBjYW5ub3QgYmUgY29uZmlndXJlZFxyXG4gKiBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFNlcnZlciA9IGFzeW5jIChzZXJ2ZXJDb25maWcpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xyXG4gICAgaWYgKFxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXHJcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxyXG4gICAgKSB7XHJcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGUoYXBwKTtcclxuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsSW50ZXJ2YWxzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNodXRkb3duQ2xlYW5VcCB9IGZyb20gJy4vcmVzb3VyY2VfcmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXHJcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nLCBhbmRcclxuICogJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyA9ICgpID0+IHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgVGhlICR7bmFtZX0gZXJyb3IuYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXHJcbiAqIHRoaXMgc3RhZ2UuIEZ1bmN0aW9uIHRoYXQgaXMgcmVxdWlyZWQgdG8gYmUgY2FsbGVkIGJlZm9yZSB0cnlpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXR0aW5nIGEgc2VydmVyLiBUaGUgYG9wdGlvbnNgIGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgZXhwb3J0IG9wdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBpbml0RXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMgJiYgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKHtcclxuICAgIHBvb2w6IG9wdGlvbnMucG9vbCB8fCB7XHJcbiAgICAgIG1pbldvcmtlcnM6IDEsXHJcbiAgICAgIG1heFdvcmtlcnM6IDFcclxuICAgIH0sXHJcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlci5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIE90aGVyXHJcbiAgc2V0T3B0aW9ucyxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsic2NyaXB0c05hbWVzIiwiY29yZSIsIm1vZHVsZXMiLCJpbmRpY2F0b3JzIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibG9nZ2luZyIsImxldmVsIiwiZmlsZSIsImRlc3QiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub2RlRW52IiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJub0xvZ28iLCJoYXJkUmVzZXRQYWdlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJGdW5jdGlvbiIsImNoYXJ0IiwiYW5pbWF0aW9uIiwic3RySW5qIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsIm5ld1BhZ2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwic2V0UGFnZUNvbnRlbnQiLCJzZXRDb250ZW50Iiwid2FpdFVudGlsIiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsImV2YWx1YXRlIiwiX19iYXNlZGlyIiwic2V0QXNDb25maWciLCJwdXBwZXRlZXJFeHBvcnQiLCJpbmplY3RlZFJlc291cmNlcyIsImNsZWFySW5qZWN0ZWQiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsImVsZW1lbnQiLCJyZW1vdmUiLCJleHBvcnRPcHRpb25zIiwiZGVidWdnZXIiLCJpc1NWRyIsInN2Z1RlbXBsYXRlIiwiaW5qZWN0ZWRKcyIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImluamVjdGVkQ3NzIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCIkZXZhbCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImhhcmRSZXNldCIsImdvdG8iLCJjbGVhclBhZ2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImNvbm5lY3RlZCIsImJyb3dzZXJDbG9zZSIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsImdldFBvb2xJbmZvSlNPTiIsIm51bUZyZWUiLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwicGVuZGluZyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiQUREX1RBR1MiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsInBhcmFtcyIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiNnRCQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FD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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 6458f6f7..2a83a136 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},A=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?A(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};A(_),u.config();const N=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:N(O.core),HIGHCHARTS_MODULE_SCRIPTS:N(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:N(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:G(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:G(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:G(),SERVER_RATE_LIMITING_WINDOW:G(),SERVER_RATE_LIMITING_DELAY:G(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:G(),POOL_MAX_WORKERS:G(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:G(),POOL_CREATE_TIMEOUT:G(),POOL_DESTROY_TIMEOUT:G(),POOL_IDLE_TIMEOUT:G(),POOL_CREATE_RETRY_INTERVAL:G(),POOL_REAPER_INTERVAL:G(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:G(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:D.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;s(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Le(e),e}async function Le(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const Oe=g.fileURLToPath(new URL(".",import.meta.url)),_e=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var ke=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await _e(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await _e(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(Oe,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o})))(e,u,d,"base64")}return await s(e),f}catch(t){return await s(e),t}};let Ie=!1;const Ce={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Ne={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>!(Ae.workLimit&&++e.workCount>Ae.workLimit)||(W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1),destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Pe=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ie)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ie=new y({...Ne,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ie.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Le(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ie.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ie.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function He(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ie){for(const e of Ie.used)Ie.release(e.resource);Ie.destroyed||(await Ie.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const $e=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ce.exportAttempts,Ae.benchmarking&&Ge(),!Ie)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ie.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await ke(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ie.release(r);const a=(new Date).getTime()-i;return Ce.timeSpent+=a,Ce.spentAverage=Ce.timeSpent/++Ce.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ce.droppedExports,r&&Ie.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ue=()=>({min:Ie.min,max:Ie.max,all:Ie.numFree()+Ie.numUsed(),available:Ie.numFree(),used:Ie.numUsed(),pending:Ie.numPendingAcquires()});function Ge(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ue();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var De=Ue,je=()=>Ce;let Me=!1;const Fe=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Be(function(e){const t=new E("").window;return T(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++Ce.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Be(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?qe(r,t):"string"==typeof o.instr?Be(o.instr.trim(),r,t):Ve(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},We=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ve=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Me;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...We(e)};try{return r(!1,await $e(s.strInj||t||o,e))}catch(e){return r(e)}},qe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ve(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Be=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),Ve(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ve(t,o,r)}catch(e){return ee(o)?qe(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Xe=[],Ke=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Xe)clearInterval(e)},Je=(e,t,r,o)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},ze=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ye=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Qe extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let et=0;const tt=[],rt=[],ot=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},it=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++et;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Qe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Qe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=ot(tt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Me,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Qe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Qe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ot(rt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const st=JSON.parse(i(l(X,"package.json"))),nt=new Date,at=[];function lt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;at.push(t),at.length>30&&at.shift()}),6e4),Xe.push(t),e.get("/health",((e,t)=>{const r=je(),o=at.length,i=at.reduce(((e,t)=>e+t),0)/at.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:nt,uptime:Math.floor(((new Date).getTime()-nt.getTime())/1e3/60)+" minutes",version:st.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:De(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ct=new Map,pt=x();pt.disable("x-powered-by"),pt.use(S());const ht=R.memoryStorage(),ut=R({storage:ht,limits:{fieldSize:52428800}});pt.use(x.json({limit:52428800})),pt.use(x.urlencoded({extended:!0,limit:52428800})),pt.use(ut.none());const dt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},gt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(pt);dt(t),t.listen(e.port,e.host),ct.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},pt);dt(o),o.listen(e.ssl.port,e.host),ct.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(pt,e.rateLimiting),pt.use(x.static(c.join(X,"public"))),lt(pt),(e=>{e.post("/",it),e.post("/:filename",it)})(pt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(pt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Qe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Qe("No new version supplied.",400);try{await ve(i)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(pt),(e=>{e.use(Je),e.use(ze)})(pt)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},mt=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of ct)t.close((()=>{ct.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var ft={startServer:gt,closeServers:mt,getServers:()=>ct,enableRateLimiting:e=>Ye(pt,e),getExpress:()=>x,getApp:()=>pt,use:(e,...t)=>{pt.use(e,...t)},get:(e,...t)=>{pt.get(e,...t)},post:(e,...t)=>{pt.post(e,...t)}};const vt=async e=>{await Promise.allSettled([Ke(),mt(),He()]),process.exit(e)};var yt={server:ft,startServer:gt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Me=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await vt(1)}))),await me(e),await Pe({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Fe(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await He()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Fe({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await He()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,initPool:Pe,killPool:He,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:vt,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{yt as default}; +import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},A=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?A(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};A(_),u.config();const N=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:N(O.core),HIGHCHARTS_MODULE_SCRIPTS:N(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:N(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:D(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:D(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:D(),SERVER_RATE_LIMITING_WINDOW:D(),SERVER_RATE_LIMITING_DELAY:D(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:D(),POOL_MAX_WORKERS:D(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:D(),POOL_CREATE_TIMEOUT:D(),POOL_DESTROY_TIMEOUT:D(),POOL_IDLE_TIMEOUT:D(),POOL_CREATE_RETRY_INTERVAL:D(),POOL_REAPER_INTERVAL:D(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:D(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in G&&void 0!==G[i.envLink]&&(i.value=G[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&s(h),Highcharts[t.export.constr||"chart"]("container",c,p);const u=o();for(const e in u)"function"!=typeof u[e]&&delete u[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Le(e),e}async function Le(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const Oe=g.fileURLToPath(new URL(".",import.meta.url)),_e=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var ke=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await _e(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await _e(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(Oe,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))])))(e,u,d,"base64",n.rasterizationTimeout)}return await s(e),f}catch(t){return await s(e),t}};let Ie=!1;const Ce={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Ne={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>!(Ae.workLimit&&++e.workCount>Ae.workLimit)||(W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1),destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Pe=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ie)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ie=new y({...Ne,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ie.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Le(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ie.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ie.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function He(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ie){for(const e of Ie.used)Ie.release(e.resource);Ie.destroyed||(await Ie.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const $e=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ce.exportAttempts,Ae.benchmarking&&De(),!Ie)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ie.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await ke(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ie.release(r);const a=(new Date).getTime()-i;return Ce.timeSpent+=a,Ce.spentAverage=Ce.timeSpent/++Ce.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ce.droppedExports,r&&Ie.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ue=()=>({min:Ie.min,max:Ie.max,all:Ie.numFree()+Ie.numUsed(),available:Ie.numFree(),used:Ie.numUsed(),pending:Ie.numPendingAcquires()});function De(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ue();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Ge=Ue,je=()=>Ce;let Me=!1;const Fe=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Be(function(e){const t=new E("").window;return T(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++Ce.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Be(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?qe(r,t):"string"==typeof o.instr?Be(o.instr.trim(),r,t):Ve(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},We=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ve=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Me;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...We(e)};try{return r(!1,await $e(s.strInj||t||o,e))}catch(e){return r(e)}},qe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ve(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Be=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),Ve(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ve(t,o,r)}catch(e){return ee(o)?qe(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Xe=[],Ke=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Xe)clearInterval(e)},Je=(e,t,r,o)=>{V(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,o(e)},ze=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ye=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Qe extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let et=0;const tt=[],rt=[],ot=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},it=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++et;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Qe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Qe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=ot(tt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Me,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Qe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Qe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ot(rt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const st=JSON.parse(i(l(X,"package.json"))),nt=new Date,at=[];function lt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;at.push(t),at.length>30&&at.shift()}),6e4),Xe.push(t),e.get("/health",((e,t)=>{const r=je(),o=at.length,i=at.reduce(((e,t)=>e+t),0)/at.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:nt,uptime:Math.floor(((new Date).getTime()-nt.getTime())/1e3/60)+" minutes",version:st.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ge(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ct=new Map,pt=x();pt.disable("x-powered-by"),pt.use(S());const ht=R.memoryStorage(),ut=R({storage:ht,limits:{fieldSize:52428800}});pt.use(x.json({limit:52428800})),pt.use(x.urlencoded({extended:!0,limit:52428800})),pt.use(ut.none());const dt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},gt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(pt);dt(t),t.listen(e.port,e.host),ct.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},pt);dt(o),o.listen(e.ssl.port,e.host),ct.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(pt,e.rateLimiting),pt.use(x.static(c.join(X,"public"))),lt(pt),(e=>{e.post("/",it),e.post("/:filename",it)})(pt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(pt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=G.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Qe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Qe("No new version supplied.",400);try{await ve(i)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(pt),(e=>{e.use(Je),e.use(ze)})(pt)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},mt=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of ct)t.close((()=>{ct.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var ft={startServer:gt,closeServers:mt,getServers:()=>ct,enableRateLimiting:e=>Ye(pt,e),getExpress:()=>x,getApp:()=>pt,use:(e,...t)=>{pt.use(e,...t)},get:(e,...t)=>{pt.get(e,...t)},post:(e,...t)=>{pt.post(e,...t)}};const vt=async e=>{await Promise.allSettled([Ke(),mt(),He()]),process.exit(e)};var yt={server:ft,startServer:gt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Me=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await vt(1)}))),await me(e),await Pe({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Fe(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await He()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Fe({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await He()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,initPool:Pe,killPool:He,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:vt,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{yt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index cba6ec54..ebc98c8b 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/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: '.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description: '.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: '.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description: '.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description: '.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: '.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: '.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: '',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: '',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: '',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: '',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: '',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: '',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/** Called when initing the page */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/** Create the actual chart */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful??\r\n window.isRenderComplete = false;\r\n\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n setOptions(JSON.parse(options.export.globalOptions));\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (page, height, width, encoding) => {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","setContent","waitUntil","addScriptTag","path","evaluate","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","innerHTML","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","setContent","waitUntil","addScriptTag","path","evaluate","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","innerHTML","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file diff --git a/lib/export.js b/lib/export.js index e9d9a9f1..cc808a25 100644 --- a/lib/export.js +++ b/lib/export.js @@ -93,14 +93,28 @@ const createImage = (page, type, encoding, clip, rasterizationTimeout) => * * @returns {Promise} Promise resolving to the PDF buffer. */ -const createPDF = async (page, height, width, encoding) => { +const createPDF = async ( + page, + height, + width, + encoding, + rasterizationTimeout +) => { await page.emulateMediaType('screen'); - return page.pdf({ - // This will remove an extra empty page in PDF exports - height: height + 1, - width, - encoding - }); + return Promise.race([ + page.pdf({ + // This will remove an extra empty page in PDF exports + height: height + 1, + width, + encoding + }), + new Promise((_resolve, reject) => + setTimeout( + () => reject(new ExportError('Rasterization timeout')), + rasterizationTimeout || 1500 + ) + ) + ]); }; /** @@ -407,7 +421,13 @@ export default async (page, chart, options) => { ); } else if (exportOptions.type === 'pdf') { // PDF - data = await createPDF(page, viewportHeight, viewportWidth, 'base64'); + data = await createPDF( + page, + viewportHeight, + viewportWidth, + 'base64', + exportOptions.rasterizationTimeout + ); } else { throw new ExportError( `[export] Unsupported output format ${exportOptions.type}.` diff --git a/lib/highcharts.js b/lib/highcharts.js index d586cbc3..6ba92066 100644 --- a/lib/highcharts.js +++ b/lib/highcharts.js @@ -14,14 +14,22 @@ See LICENSE file in root for details. /* eslint-disable no-undef */ -/** Called when initing the page */ +/** + * Setting the animObject. Called when initing the page. + */ export function setupHighcharts() { Highcharts.animObject = function () { return { duration: 0 }; }; } -/** Create the actual chart */ +/** + * Creates the actual chart. + * + * @param {object} chartOptions - The options for the Highcharts chart. + * @param {object} options - The export options. + * @param {boolean} displayErrors - A flag indicating whether to display errors. + */ export function triggerExport(chartOptions, options, displayErrors) { // Display errors flag taken from chart options nad debugger module window._displayErrors = displayErrors; @@ -49,9 +57,8 @@ export function triggerExport(chartOptions, options, displayErrors) { chart.width = chartOptions.chart.width; } - // NOTE: Is this used for anything useful?? + // NOTE: Is this used for anything useful? window.isRenderComplete = false; - wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) { // Override userOptions with image friendly options userOptions = merge(userOptions, { @@ -109,7 +116,10 @@ export function triggerExport(chartOptions, options, displayErrors) { : undefined; // Set the global options if exist - setOptions(JSON.parse(options.export.globalOptions)); + const globalOptions = JSON.parse(options.export.globalOptions); + if (globalOptions) { + setOptions(globalOptions); + } Highcharts[options.export.constr || 'chart']( 'container', diff --git a/lib/index.js b/lib/index.js index 5bea8b96..57eeb303 100644 --- a/lib/index.js +++ b/lib/index.js @@ -126,16 +126,16 @@ export default { initPool, killPool, + // Other + setOptions, + shutdownCleanUp, + // Logs log, logWithStack, setLogLevel, enableFileLogging, - // Other - setOptions, - shutdownCleanUp, - // Utils mapToNewConfig, manualConfig, diff --git a/lib/schemas/config.js b/lib/schemas/config.js index f14a6381..3669cc54 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -626,43 +626,48 @@ export const defaultConfig = { type: 'boolean', envLink: 'DEBUG_ENABLE', cliName: 'enableDebug', - description: '.' + description: 'Enables or disables debug mode for the underlying browser.' }, headless: { value: true, type: 'boolean', envLink: 'DEBUG_HEADLESS', - description: '.' + description: + 'Controls the mode in which the browser is launched when in the debug mode.' }, devtools: { value: false, type: 'boolean', envLink: 'DEBUG_DEVTOOLS', - description: '.' + description: + 'Decides whether to enable DevTools when the browser is in a headful state.' }, listenToConsole: { value: false, type: 'boolean', envLink: 'DEBUG_LISTEN_TO_CONSOLE', - description: '.' + description: + 'Decides whether to enable a listener for console messages sent from the browser.' }, dumpio: { value: false, type: 'boolean', envLink: 'DEBUG_DUMPIO', - description: '.' + description: + 'Redirects browser process stdout and stderr to process.stdout and process.stderr.' }, slowMo: { value: 0, type: 'number', envLink: 'DEBUG_SLOW_MO', - description: '.' + description: + 'Slows down Puppeteer operations by the specified number of milliseconds.' }, debuggingPort: { value: 9222, type: 'number', envLink: 'DEBUG_DEBUGGING_PORT', - description: '.' + description: 'Specifies the debugging port.' } } }; @@ -1041,43 +1046,43 @@ export const promptsConfig = { { type: 'toggle', name: 'enable', - message: 'Enable debug mode for the browser instance', + message: 'Enables debug mode for the browser instance', initial: defaultConfig.debug.enable.value }, { type: 'toggle', name: 'headless', - message: '', + message: 'The mode setting for the browser', initial: defaultConfig.debug.headless.value }, { type: 'toggle', name: 'devtools', - message: '', + message: 'The DevTools for the headful browser', initial: defaultConfig.debug.devtools.value }, { type: 'toggle', name: 'listenToConsole', - message: '', + message: 'The event listener for console messages from the browser', initial: defaultConfig.debug.listenToConsole.value }, { type: 'toggle', name: 'dumpio', - message: '', + message: 'Redirects the browser stdout and stderr to NodeJS process', initial: defaultConfig.debug.dumpio.value }, { type: 'number', name: 'slowMo', - message: '', + message: 'Puppeteer operations slow down in milliseconds', initial: defaultConfig.debug.slowMo.value }, { type: 'number', name: 'debuggingPort', - message: '', + message: 'The port number for debugging', initial: defaultConfig.debug.debuggingPort.value } ] From 5334f733304bb1547a3bf7ee8585148db5d598b6 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 14 May 2024 18:20:03 +0200 Subject: [PATCH 6/7] Refactored and optimized code of export, browser, pool and other modules. --- dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/browser.js | 206 +++++++++++++++++- lib/cache.js | 12 +- lib/export.js | 167 ++------------- lib/highcharts.js | 2 +- lib/pool.js | 35 +--- lib/server/routes/change_hc_version.js | 6 +- lib/server/routes/health.js | 4 +- package-lock.json | 277 +++++++++++++++++++++---- 11 files changed, 469 insertions(+), 248 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index 4ea67951..62ca7e1c 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?L(o,`${t}.${r}`):(R[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(R[o.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),i.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=H;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=H;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([o[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=W(t),i&&!r&&delete i.files;for(const e in i)o.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):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const o=V(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Z(o[e],n,r);var i;return o};function ee(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?ee(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in N&&void 0!==N[i.envLink]&&(i.value=N[i.envLink]))}))}function te(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:te(o);return t}function re(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=re(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function oe(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ie extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const i=await oe(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ie(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,l=i.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new ie("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...o.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,l),ne.hcVersion=se(ne),e.writeFileSync(i,ne.sources),l}catch(e){throw new ie("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:o,server:i}=r,n=t.join(F,o.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(o,i.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=o,u=n.length+c.length+p.length;r.version!==o.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(o,i.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ne.activeManifest=i,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new ie("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await we(e),e}async function we(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Ee=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Te=(e,t,r,o)=>e.evaluate(me,t,r,o);var Se=async(r,o,i)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{U(4,"[export] Determining export path.");const a=i.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return o;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Te(r,{chart:{height:a.height,width:a.width}},i,l):(o.chart.height=a.height,o.chart.width=a.width,await Te(r,o,i,l));const p=i.customLogic.resources;if(p){const o=[];if(p.js&&o.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");o.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of o)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}o.length=0;const s=[];if(p.css){let e=p.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")?s.push({url:r}):i.customLogic.allowFileResources&&s.push({path:t.join(Ee,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new ie(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))])))(r,h,d,"base64",a.rasterizationTimeout)}return await s(r),f}catch(e){return await s(r),e}};let xe=!1;const Re={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const Oe={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new ie("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ie("Error encountered when creating a new page.").setError(e)}const{debug:o}=Q();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(Le.workLimit&&++e.workCount>Le.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},_e=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=Q().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!ye){let e=0;const r=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ye=await u.launch(o)}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ie("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ye)throw new ie("[browser] Cannot find a browser to open.")}return ye}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),xe)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{xe=new c.Pool({...Oe,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),xe.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await we(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),U(4,`[pool] Releasing a worker with ID ${e.id}.`)})),xe.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{xe.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ie("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),xe){for(const e of xe.used)xe.release(e.resource);xe.destroyed||(await xe.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ye?.connected&&await ye.close(),U(4,"[browser] Closed the browser.")}()}const Ie=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Re.exportAttempts,Le.benchmarking&&Ae(),!xe)throw new ie("Work received, but pool has not been started.");const o=J();try{U(4,"[pool] Acquiring a worker handle."),r=await xe.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new ie((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new ie("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await Se(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await be()),new ie((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),xe.release(r);const a=(new Date).getTime()-i;return Re.timeSpent+=a,Re.spentAverage=Re.timeSpent/++Re.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Re.droppedExports,r&&xe.release(r),new ie(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ce=()=>({min:xe.min,max:xe.max,all:xe.numFree()+xe.numUsed(),available:xe.numFree(),used:xe.numUsed(),pending:xe.numPendingAcquires()});function Ae(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Ce();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${o}.`),U(5,`[pool] The number of acquired resources: ${i}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var Ne=Ce,Pe=()=>Re;let He=!1;const $e=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Z(t,e,x),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Q()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=Ge(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++Re.exportFromSvgAttempts,e}catch(e){return r(new ie("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),Ge(o.export.instr.trim(),o,r)}catch(e){return r(new ie("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(o.customLogic?.allowCodeExecution)?De(o,r):"string"==typeof i.instr?Ge(i.instr.trim(),o,r):je(o,i.instr||i.options,r)}catch(e){return r(new ie("[chart] Error loading raw input.").setError(e))}return r(new ie("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||W(e.export?.instr),o=W(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},je=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=q(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=q(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new ie("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(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]=W(e.readFileSync(n[t],"utf8"),!0):n[t]=W(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=K(s.customCode,s.allowFileResources)}catch(e){j(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ue(t)};try{return o(!1,await Ie(n.strInj||r||i,t))}catch(e){return o(e)}},De=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=B(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,je(e,!1,t)}catch(r){return t(new ie(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Ge=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),je(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return je(t,o,r)}catch(e){return z(o)?De(t,r):r(new ie("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Fe=[],Me=()=>{U(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},qe=(e,t,r,o)=>{j(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,o(e)},We=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,l=i||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Ve=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),U(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Be extends ie{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Xe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Ke=[],Je=[],Ye=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Qe=async(e,t,r)=>{try{const r=J(),i=p.v4().replace(/-/g,""),n=Q(),s=e.body,a=++ze;let l=M(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=W(s.infile||s.options||s.data);if(!c&&!s.svg)throw U(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ye(Ke,e,t,{id:a,uniqueId:i,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:W(s.globalOptions,!0),themeOptions:W(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:W(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=B(c,d.customLogic.allowCodeExecution));const g=Z(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await $e(g,((o,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Ye(Je,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Xe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const Ze=JSON.parse(e.readFileSync(t.join(F,"package.json"))),et=new Date,tt=[];function rt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Pe(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;tt.push(t),tt.length>30&&tt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=Pe(),o=tt.length,i=tt.reduce(((e,t)=>e+t),0)/tt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:de(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ne(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ot=new Map,it=m();it.disable("x-powered-by"),it.use(g());const nt=f.memoryStorage(),st=f({storage:nt,limits:{fieldSize:52428800}});it.use(m.json({limit:52428800})),it.use(m.urlencoded({extended:!0,limit:52428800})),it.use(st.none());const at=e=>{e.on("clientError",(e=>{j(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{j(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{j(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(it);at(e),e.listen(r.port,r.host),ot.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},it);at(e),e.listen(r.ssl.port,r.host),ot.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ve(it,r.rateLimiting),it.use(m.static(t.posix.join(F,"public"))),rt(it),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(it),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(it),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Be("No new version supplied.",400);try{await ue(i)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:de(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(it),(e=>{e.use(qe),e.use(We)})(it)}catch(e){throw new ie("[server] Could not configure and start the server.").setError(e)}},ct=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ot)t.close((()=>{ot.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>ot,enableRateLimiting:e=>Ve(it,e),getExpress:()=>m,getApp:()=>it,use:(e,...t)=>{it.use(e,...t)},get:(e,...t)=>{it.get(e,...t)},post:(e,...t)=>{it.post(e,...t)}};const ut=async e=>{await Promise.allSettled([Me(),ct(),ke()]),process.exit(e)};var ht={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=z(t),(e=>{D(e&&parseInt(e.level)),e&&e.dest&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(U(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{U(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await ut(1)}))),await ce(e),await _e({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await $e(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push($e({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new ie("[chart] Error encountered during batch export.").setError(e)}},startExport:$e,initPool:_e,killPool:ke,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Z(Y,t,x)),r?.length&&(Y=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=z(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&X();return e}(Y,r,T)),Y),shutdownCleanUp:ut,log:U,logWithStack:j,setLogLevel:D,enableFileLogging:G,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=re(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:X};module.exports=ht; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIGEgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgc2VudCBmcm9tIHRoZSBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYW5pbU9iamVjdC4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY2hhcnRPcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBIaWdoY2hhcnRzIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBkaXNwbGF5RXJyb3JzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciB0byBkaXNwbGF5IGVycm9ycy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0cmlnZ2VyRXhwb3J0KGNoYXJ0T3B0aW9ucywgb3B0aW9ucywgZGlzcGxheUVycm9ycykge1xyXG4gIC8vIERpc3BsYXkgZXJyb3JzIGZsYWcgdGFrZW4gZnJvbSBjaGFydCBvcHRpb25zIG5hZCBkZWJ1Z2dlciBtb2R1bGVcclxuICB3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkaXNwbGF5RXJyb3JzO1xyXG5cclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBtZXJnZSwgc2V0T3B0aW9ucywgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBzZXRPcHRpb25zIHVzYWdlcyBpbiBvcmRlciB0b1xyXG4gIC8vIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gVHJpZ2dlciBjdXN0b20gY29kZVxyXG4gIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpIHtcclxuICAgIG5ldyBGdW5jdGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKCk7XHJcbiAgfVxyXG5cclxuICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGNvbnN0IGNoYXJ0ID0ge1xyXG4gICAgYW5pbWF0aW9uOiBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFdoZW4gc3RyYWlnaHQgaW5qZWN0LCB0aGUgc2l6ZSBpcyBzZXQgdGhyb3VnaCBDU1Mgb25seVxyXG4gIGlmIChvcHRpb25zLmV4cG9ydC5zdHJJbmopIHtcclxuICAgIGNoYXJ0LmhlaWdodCA9IGNoYXJ0T3B0aW9ucy5jaGFydC5oZWlnaHQ7XHJcbiAgICBjaGFydC53aWR0aCA9IGNoYXJ0T3B0aW9ucy5jaGFydC53aWR0aDtcclxuICB9XHJcblxyXG4gIC8vIE5PVEU6IElzIHRoaXMgdXNlZCBmb3IgYW55dGhpbmcgdXNlZnVsP1xyXG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XHJcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XHJcbiAgICAvLyBPdmVycmlkZSB1c2VyT3B0aW9ucyB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcclxuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcclxuICAgICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgfSxcclxuICAgICAgcGxvdE9wdGlvbnM6IHtcclxuICAgICAgICBzZXJpZXM6IHtcclxuICAgICAgICAgIGxhYmVsOiB7XHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdXNlck9wdGlvbnMgd2hlbiBmb3JFeHBvcnQgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEdldCB0aGUgdXNlciBvcHRpb25zXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5zdHJJbmp9YCkoKVxyXG4gICAgOiBjaGFydE9wdGlvbnM7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxyXG4gIC8vIHNldE9wdGlvbnMgZnVuY3Rpb24gYW5kIHVzZXIgb3B0aW9ucyB0byBjcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zKSxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgeyBjaGFydCB9XHJcbiAgKTtcclxuXHJcbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IG9wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2tcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcclxuICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9ucyk7XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICBIaWdoY2hhcnRzW29wdGlvbnMuZXhwb3J0LmNvbnN0ciB8fCAnY2hhcnQnXShcclxuICAgICdjb250YWluZXInLFxyXG4gICAgZmluYWxPcHRpb25zLFxyXG4gICAgZmluYWxDYWxsYmFja1xyXG4gICk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIHNldE9wdGlvbnMgd2FzIHVzZWQgaW4gdGhlIGN1c3RvbUNvZGUpXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciB0aGUgcGFnZVxyXG5jb25zdCBfX2Rpcm5hbWUgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldCgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZShwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWcgfSA9IGdldE9wdGlvbnMoKS5kZWJ1ZztcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6ICdzaGVsbCcsXHJcbiAgICB1c2VyRGF0YURpcjogJy4vdG1wLycsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZSgpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIElmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdCBhdmFpbGFibGUsIHJldHVybnMgZmFsc2UuXHJcbiAqXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiBzZXRQYWdlQ29udGVudCgpLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XHJcbiAqIGF2YWlsYWJsZSwgb3IgYSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBuZXdseSBjcmVhdGVkIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmICghcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICAgIGF3YWl0IHBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLy4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IF9fYmFzZWRpciA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudCB3aXRoXHJcbiAqIHRoZSBpZCAnY2hhcnQtY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHgsIHksIHdpZHRoLCBhbmQgaGVpZ2h0IHByb3BlcnRpZXMuXHJcbiAqL1xyXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gaW1hZ2UgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBzY3JlZW5zaG90IGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gSW1hZ2UgZW5jb2RpbmcuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGltYWdlIGJ1ZmZlciBvciByZWplY3RpbmdcclxuICogd2l0aCBhbiBFeHBvcnRFcnJvciBmb3IgdGltZW91dC5cclxuICovXHJcbmNvbnN0IGNyZWF0ZUltYWdlID0gKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwLCByYXN0ZXJpemF0aW9uVGltZW91dCkgPT5cclxuICBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcclxuICAgICAgdHlwZSxcclxuICAgICAgZW5jb2RpbmcsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGNhcHR1cmVCZXlvbmRWaWV3cG9ydDogdHJ1ZSxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcblxyXG4gICAgICAvLyAjNDQ3LCAjNDYzIC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGVcclxuICAgICAgLy8gZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJ1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXHJcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxyXG4gICAgICApXHJcbiAgICApXHJcbiAgXSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlUERGID0gYXN5bmMgKFxyXG4gIHBhZ2UsXHJcbiAgaGVpZ2h0LFxyXG4gIHdpZHRoLFxyXG4gIGVuY29kaW5nLFxyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbikgPT4ge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnBkZih7XHJcbiAgICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBlbmNvZGluZ1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXHJcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxyXG4gICAgICApXHJcbiAgICApXHJcbiAgXSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycykgPT5cclxuICBwYWdlLmV2YWx1YXRlKHRyaWdnZXJFeHBvcnQsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAqIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICovXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xyXG4gIGNvbnN0IGNsZWFySW5qZWN0ZWQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIGxldCBpc1NWRztcclxuICAgIGlmIChcclxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxyXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRy4nKTtcclxuXHJcbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBjaGFydDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICBkaXNwbGF5RXJyb3JzXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvbnN0IGluamVjdGVkSnMgPSBbXTtcclxuXHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaCh7XHJcbiAgICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgICAgaW5qZWN0ZWRKcy5wdXNoKFxyXG4gICAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xyXG5cclxuICAgICAgLy8gTG9hZCBDU1NcclxuICAgICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgICAgaWYgKHJlc291cmNlcy5jc3MpIHtcclxuICAgICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxyXG4gICAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcclxuICAgICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19iYXNlZGlyLCBjc3NJbXBvcnRQYXRoKVxyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xyXG4gICAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBzdmdFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcclxuICAgICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnXHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWVzIGNvcnJlY3RseSBzY2FsZWRcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0SGVpZ2h0ID0gc3ZnRWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG4gICAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XHJcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XHJcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcclxuICBleHBvcnRBdHRlbXB0czogMCxcclxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXHJcbiAgdGltZVNwZW50OiAwLFxyXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxyXG4gIHNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuICAgIC8vIFNldCB0aGUgY29uc29sZSBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdGhlIHBhZ2VlcnJvciBsaXN0ZW5lclxyXG4gICAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcclxuICAgICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICAgJyNjb250YWluZXInLFxyXG4gICAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgaWYgKHdpbmRvdy5fZGlzcGxheUVycm9ycykge1xyXG4gICAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LFxyXG4gICAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjogPC9oMT4ke2Vycm9yLnRvU3RyaW5nKCl9YFxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxyXG4gICAgICAgICAgOiAnJykgKyBgRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYWxsOiBwb29sLm51bUZyZWUoKSArIHBvb2wubnVtVXNlZCgpLFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgdXNlZDogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZzogcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHsgbWluLCBtYXgsIGFsbCwgYXZhaWxhYmxlLCB1c2VkLCBwZW5kaW5nIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgcmVzb3VyY2VzOiAke2FsbH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhdmFpbGFibGUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhY3F1aXJlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nfS5gKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbEluZm8sXHJcbiAgZ2V0UG9vbEluZm9KU09OLFxyXG4gIGdldFN0YXRzOiAoKSA9PiBzdGF0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGV4cG9ydEFzU3RyaW5nKFxyXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICApO1xyXG5cclxuICAgICAgKytzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHM7XHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcclxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgc2luZ2xlIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXHJcbiAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBvdXRmaWxlLCB0eXBlIH0gPSBpbmZvLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcclxuICAgICk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICoqL1xyXG5cclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxyXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxyXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7IEFERF9UQUdTOiBbJ2ZvcmVpZ25PYmplY3QnXSB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgc2FuaXRpemU7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbmNvbnN0IGludGVydmFsSWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiBhIHNldEludGVydmFsIHRvIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBhZGRJbnRlcnZhbCA9IChpZCkgPT4ge1xyXG4gIGludGVydmFsSWRzLnB1c2goaWQpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYnkgaWRzIGdhdGhlcmVkIGluIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhckFsbEludGVydmFscyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIGludGVydmFsSWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkSW50ZXJ2YWwsXHJcbiAgY2xlYXJBbGxJbnRlcnZhbHNcclxufTtcclxuIiwiaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBhZGRJbnRlcnZhbCB9IGZyb20gJy4uLy4uL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XHJcblxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwOyAvLyByZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDsgLy8gMzAgbWludXRlc1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIHN1Y2Nlc3NSYXRlc1xyXG4gKiBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgY29uc3Qgc3VtID0gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xyXG4gIHJldHVybiBzdW0gLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGdhdGhlcnNcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U3VjY2Vzc1JhdGUgPSAoKSA9PlxyXG4gIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xyXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgaWYgKCFhcHApIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxyXG4gIGFkZEludGVydmFsKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgIGxvZyg0LCAnW2hlYWx0aC5qc10gR0VUIC9oZWFsdGggWzIwMF0gLSByZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICByZXMuc2VuZCh7XHJcbiAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgdXB0aW1lOlxyXG4gICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxyXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxyXG4gICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzLFxyXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcclxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxyXG4gICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDAsXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgIHBlcmlvZCxcclxuICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgbWVzc2FnZTogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgIC8vIFNWRy9KU09OIGF0dGVtcHRzXHJcbiAgICAgIHN2Z0V4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgIGpzb25FeHBvcnRBdHRlbXB0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAtIHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0c1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tICcuL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXHJcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbmFwcC51c2UoY29ycygpKTtcclxuXHJcbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcclxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgc3RvcmFnZSxcclxuICBsaW1pdHM6IHtcclxuICAgIGZpZWxkU2l6ZTogNTAgKiAxMDI0ICogMTAyNFxyXG4gIH1cclxufSk7XHJcblxyXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcbmFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuXHJcbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG5hcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi4gVGhlIGBzZXJ2ZXJDb25maWdgXHJcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXHJcbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNlcnZlciBjYW5ub3QgYmUgY29uZmlndXJlZFxyXG4gKiBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFNlcnZlciA9IGFzeW5jIChzZXJ2ZXJDb25maWcpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xyXG4gICAgaWYgKFxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXHJcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxyXG4gICAgKSB7XHJcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGUoYXBwKTtcclxuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsSW50ZXJ2YWxzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNodXRkb3duQ2xlYW5VcCB9IGZyb20gJy4vcmVzb3VyY2VfcmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXHJcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nLCBhbmRcclxuICogJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyA9ICgpID0+IHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgVGhlICR7bmFtZX0gZXJyb3IuYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXHJcbiAqIHRoaXMgc3RhZ2UuIEZ1bmN0aW9uIHRoYXQgaXMgcmVxdWlyZWQgdG8gYmUgY2FsbGVkIGJlZm9yZSB0cnlpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXR0aW5nIGEgc2VydmVyLiBUaGUgYG9wdGlvbnNgIGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgZXhwb3J0IG9wdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBpbml0RXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMgJiYgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKHtcclxuICAgIHBvb2w6IG9wdGlvbnMucG9vbCB8fCB7XHJcbiAgICAgIG1pbldvcmtlcnM6IDEsXHJcbiAgICAgIG1heFdvcmtlcnM6IDFcclxuICAgIH0sXHJcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlci5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIE90aGVyXHJcbiAgc2V0T3B0aW9ucyxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsic2NyaXB0c05hbWVzIiwiY29yZSIsIm1vZHVsZXMiLCJpbmRpY2F0b3JzIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibG9nZ2luZyIsImxldmVsIiwiZmlsZSIsImRlc3QiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub2RlRW52IiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJub0xvZ28iLCJoYXJkUmVzZXRQYWdlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJGdW5jdGlvbiIsImNoYXJ0IiwiYW5pbWF0aW9uIiwic3RySW5qIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsIm5ld1BhZ2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwic2V0UGFnZUNvbnRlbnQiLCJzZXRDb250ZW50Iiwid2FpdFVudGlsIiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsImV2YWx1YXRlIiwiX19iYXNlZGlyIiwic2V0QXNDb25maWciLCJwdXBwZXRlZXJFeHBvcnQiLCJpbmplY3RlZFJlc291cmNlcyIsImNsZWFySW5qZWN0ZWQiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsImVsZW1lbnQiLCJyZW1vdmUiLCJleHBvcnRPcHRpb25zIiwiZGVidWdnZXIiLCJpc1NWRyIsInN2Z1RlbXBsYXRlIiwiaW5qZWN0ZWRKcyIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImluamVjdGVkQ3NzIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCIkZXZhbCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImhhcmRSZXNldCIsImdvdG8iLCJjbGVhclBhZ2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImNvbm5lY3RlZCIsImJyb3dzZXJDbG9zZSIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsImdldFBvb2xJbmZvSlNPTiIsIm51bUZyZWUiLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwicGVuZGluZyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiQUREX1RBR1MiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsInBhcmFtcyIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiNnRCQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsV0FFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwrQkFDQSx1QkFDQSx1RkFDQSx5QkFDQSxvQ0FDQSxvQkFDQSwwQkFDQSw4Q0FDQSwyQkFDQSwwQkFDQSw2QkFDQSxtQ0FDQSx3Q0FDQSxtQ0FDQSwyQkFDQSxrQ0FDQSx1QkFDQSxpQkFDQSx5QkFDQSw4QkFDQSxvQkFDQSwyQkFDQSxlQUNBLDZCQUNBLGlCQUNBLGFBQ0EsZUFDQSxzQkFDQSxjQUNBLHlCQUNBLG9CQUNBLHVCQUVGQyxLQUFNLFdBQ05DLFlBQWEsMENBR2pCQyxXQUFZLENBQ1ZDLFFBQVMsQ0FDUEosTUFBTyxTQUNQQyxLQUFNLFNBQ05JLFFBQVMscUJBQ1RILFlBQWEsc0NBRWZJLE9BQVEsQ0FDTk4sTUFBTywrQkFDUEMsS0FBTSxTQUNOSSxRQUFTLHFCQUNUSCxZQUFhLGtEQUVmSyxZQUFhLENBQ1hQLE1BQU9QLEVBQWFDLEtBQ3BCTyxLQUFNLFdBQ05JLFFBQVMsMEJBQ1RILFlBQWEseUNBRWZNLGNBQWUsQ0FDYlIsTUFBT1AsRUFBYUUsUUFDcEJNLEtBQU0sV0FDTkksUUFBUyw0QkFDVEgsWUFBYSx1Q0FFZk8saUJBQWtCLENBQ2hCVCxNQUFPUCxFQUFhRyxXQUNwQkssS0FBTSxXQUNOSSxRQUFTLCtCQUNUSCxZQUFhLDBDQUVmUSxjQUFlLENBQ2JWLE1BQU8sQ0FDTCx3RUFDQSxrR0FFRkMsS0FBTSxXQUNOQyxZQUFhLHVEQUVmUyxXQUFZLENBQ1ZYLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLHlCQUNUSCxZQUNFLGlGQUVKVSxVQUFXLENBQ1RaLE1BQU8sU0FDUEMsS0FBTSxTQUNOSSxRQUFTLHdCQUNUSCxZQUNFLG9HQUdOVyxPQUFRLENBQ05DLE9BQVEsQ0FDTmQsT0FBTyxFQUNQQyxLQUFNLFNBQ05DLFlBQ0Usd0hBRUphLE1BQU8sQ0FDTGYsT0FBTyxFQUNQQyxLQUFNLFNBQ05DLFlBQ0UscUdBRUpjLFFBQVMsQ0FDUGhCLE9BQU8sRUFDUEMsS0FBTSxTQUNOQyxZQUFhLG9DQUVmZSxRQUFTLENBQ1BqQixPQUFPLEVBQ1BDLEtBQU0sU0FDTkMsWUFDRSxxR0FFSkQsS0FBTSxDQUNKRCxNQUFPLE1BQ1BDLEtBQU0sU0FDTkksUUFBUyxjQUNUSCxZQUFhLDZEQUVmZ0IsT0FBUSxDQUNObEIsTUFBTyxRQUNQQyxLQUFNLFNBQ05JLFFBQVMsZ0JBQ1RILFlBQ0UsOEVBRUppQixjQUFlLENBQ2JuQixNQUFPLElBQ1BDLEtBQU0sU0FDTkksUUFBUyx3QkFDVEgsWUFDRSx3RUFFSmtCLGFBQWMsQ0FDWnBCLE1BQU8sSUFDUEMsS0FBTSxTQUNOSSxRQUFTLHVCQUNUSCxZQUNFLHVFQUVKbUIsYUFBYyxDQUNackIsTUFBTyxFQUNQQyxLQUFNLFNBQ05JLFFBQVMsdUJBQ1RILFlBQ0UsdUVBRUpvQixPQUFRLENBQ050QixPQUFPLEVBQ1BDLEtBQU0sU0FDTkMsWUFDRSxrRkFFSnFCLE1BQU8sQ0FDTHZCLE9BQU8sRUFDUEMsS0FBTSxTQUNOQyxZQUNFLGlGQUVKc0IsTUFBTyxDQUNMeEIsT0FBTyxFQUNQQyxLQUFNLFNBQ05DLFlBQ0UsNkdBRUp1QixjQUFlLENBQ2J6QixPQUFPLEVBQ1BDLEtBQU0sU0FDTkMsWUFDRSwyR0FFSndCLGFBQWMsQ0FDWjFCLE9BQU8sRUFDUEMsS0FBTSxTQUNOQyxZQUNFLGlIQUVKeUIsTUFBTyxDQUNMM0IsT0FBTyxFQUNQQyxLQUFNLFNBQ05DLFlBQ0UsMkZBRUowQixxQkFBc0IsQ0FDcEI1QixNQUFPLEtBQ1BDLEtBQU0sU0FDTkksUUFBUywrQkFDVEgsWUFDRSxrRUFHTjJCLFlBQWEsQ0FDWEMsbUJBQW9CLENBQ2xCOUIsT0FBTyxFQUNQQyxLQUFNLFVBQ05JLFFBQVMsb0NBQ1RILFlBQ0UsNkZBRUo2QixtQkFBb0IsQ0FDbEIvQixPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxvQ0FDVEgsWUFDRSxzSEFFSjhCLFdBQVksQ0FDVmhDLE9BQU8sRUFDUEMsS0FBTSxTQUNOQyxZQUNFLG1KQUVKK0IsU0FBVSxDQUNSakMsT0FBTyxFQUNQQyxLQUFNLFNBQ05DLFlBQ0UsMEdBRUpnQyxVQUFXLENBQ1RsQyxPQUFPLEVBQ1BDLEtBQU0sU0FDTkMsWUFDRSx5R0FFSmlDLFdBQVksQ0FDVm5DLE9BQU8sRUFDUEMsS0FBTSxTQUNObUMsV0FBWSxXQUNabEMsWUFBYSx5REFFZm1DLGFBQWMsQ0FDWnJDLE9BQU8sRUFDUEMsS0FBTSxTQUNOQyxZQUNFLHdGQUdOb0MsT0FBUSxDQUNOQyxPQUFRLENBQ052QyxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxnQkFDVG1DLFFBQVMsZUFDVHRDLFlBQ0Usd0VBRUp1QyxLQUFNLENBQ0p6QyxNQUFPLFVBQ1BDLEtBQU0sU0FDTkksUUFBUyxjQUNUSCxZQUNFLDBGQUVKd0MsS0FBTSxDQUNKMUMsTUFBTyxLQUNQQyxLQUFNLFNBQ05JLFFBQVMsY0FDVEgsWUFBYSxpQ0FFZnlDLGFBQWMsQ0FDWjNDLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLHNCQUNUbUMsUUFBUyxxQkFDVHRDLFlBQ0UscUlBRUowQyxNQUFPLENBQ0xILEtBQU0sQ0FDSnpDLE9BQU8sRUFDUEMsS0FBTSxTQUNOSSxRQUFTLG9CQUNUbUMsUUFBUyxZQUNUdEMsWUFBYSxzREFFZndDLEtBQU0sQ0FDSjFDLE1BQU8sS0FDUEMsS0FBTSxTQUNOSSxRQUFTLG9CQUNUbUMsUUFBUyxZQUNUdEMsWUFBYSxzREFFZjJDLFFBQVMsQ0FDUDdDLE1BQU8sSUFDUEMsS0FBTSxTQUNOSSxRQUFTLHVCQUNUbUMsUUFBUyxlQUNUdEMsWUFBYSwyREFHakI0QyxhQUFjLENBQ1pQLE9BQVEsQ0FDTnZDLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLDhCQUNUbUMsUUFBUyxxQkFDVHRDLFlBQWEseUNBRWY2QyxZQUFhLENBQ1gvQyxNQUFPLEdBQ1BDLEtBQU0sU0FDTkksUUFBUyxvQ0FDVCtCLFdBQVksWUFDWmxDLFlBQWEseURBRWY4QyxPQUFRLENBQ05oRCxNQUFPLEVBQ1BDLEtBQU0sU0FDTkksUUFBUyw4QkFDVEgsWUFBYSx1REFFZitDLE1BQU8sQ0FDTGpELE1BQU8sRUFDUEMsS0FBTSxTQUNOSSxRQUFTLDZCQUNUSCxZQUNFLHFGQUVKZ0QsV0FBWSxDQUNWbEQsT0FBTyxFQUNQQyxLQUFNLFVBQ05JLFFBQVMsbUNBQ1RILFlBQWEsNkRBRWZpRCxRQUFTLENBQ1BuRCxPQUFPLEVBQ1BDLEtBQU0sU0FDTkksUUFBUyxnQ0FDVEgsWUFDRSx5RkFFSmtELFVBQVcsQ0FDVHBELE9BQU8sRUFDUEMsS0FBTSxTQUNOSSxRQUFTLGtDQUNUSCxZQUNFLHdGQUdObUQsSUFBSyxDQUNIZCxPQUFRLENBQ052QyxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxvQkFDVG1DLFFBQVMsWUFDVHRDLFlBQWEseUNBRWZvRCxNQUFPLENBQ0x0RCxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxtQkFDVG1DLFFBQVMsV0FDVEosV0FBWSxVQUNabEMsWUFDRSxvRUFFSndDLEtBQU0sQ0FDSjFDLE1BQU8sSUFDUEMsS0FBTSxTQUNOSSxRQUFTLGtCQUNUbUMsUUFBUyxVQUNUdEMsWUFBYSw0Q0FFZnFELFNBQVUsQ0FDUnZELE9BQU8sRUFDUEMsS0FBTSxTQUNOSSxRQUFTLHVCQUNUK0IsV0FBWSxVQUNabEMsWUFBYSwrQ0FJbkJzRCxLQUFNLENBQ0pDLFdBQVksQ0FDVnpELE1BQU8sRUFDUEMsS0FBTSxTQUNOSSxRQUFTLG1CQUNUSCxZQUFhLDREQUVmd0QsV0FBWSxDQUNWMUQsTUFBTyxFQUNQQyxLQUFNLFNBQ05JLFFBQVMsbUJBQ1QrQixXQUFZLFVBQ1psQyxZQUFhLGdEQUVmeUQsVUFBVyxDQUNUM0QsTUFBTyxHQUNQQyxLQUFNLFNBQ05JLFFBQVMsa0JBQ1RILFlBQ0UseUZBRUowRCxlQUFnQixDQUNkNUQsTUFBTyxJQUNQQyxLQUFNLFNBQ05JLFFBQVMsdUJBQ1RILFlBQ0Usb0VBRUoyRCxjQUFlLENBQ2I3RCxNQUFPLElBQ1BDLEtBQU0sU0FDTkksUUFBUyxzQkFDVEgsWUFDRSxtRUFFSjRELGVBQWdCLENBQ2Q5RCxNQUFPLElBQ1BDLEtBQU0sU0FDTkksUUFBUyx1QkFDVEgsWUFDRSxxRUFFSjZELFlBQWEsQ0FDWC9ELE1BQU8sSUFDUEMsS0FBTSxTQUNOSSxRQUFTLG9CQUNUSCxZQUNFLDZFQUVKOEQsb0JBQXFCLENBQ25CaEUsTUFBTyxJQUNQQyxLQUFNLFNBQ05JLFFBQVMsNkJBQ1RILFlBQ0UsbUdBRUorRCxlQUFnQixDQUNkakUsTUFBTyxJQUNQQyxLQUFNLFNBQ05JLFFBQVMsdUJBQ1RILFlBQ0Usb0dBRUp5QyxhQUFjLENBQ1ozQyxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxvQkFDVG1DLFFBQVMsbUJBQ1R0QyxZQUNFLDBFQUdOZ0UsUUFBUyxDQUNQQyxNQUFPLENBQ0xuRSxNQUFPLEVBQ1BDLEtBQU0sU0FDTkksUUFBUyxnQkFDVG1DLFFBQVMsV0FDVHRDLFlBQWEsaUNBRWZrRSxLQUFNLENBQ0pwRSxNQUFPLCtCQUNQQyxLQUFNLFNBQ05JLFFBQVMsZUFDVG1DLFFBQVMsVUFDVHRDLFlBQ0UsMkZBRUptRSxLQUFNLENBQ0pyRSxNQUFPLE9BQ1BDLEtBQU0sU0FDTkksUUFBUyxlQUNUbUMsUUFBUyxVQUNUdEMsWUFDRSxpRUFHTm9FLEdBQUksQ0FDRi9CLE9BQVEsQ0FDTnZDLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLFlBQ1RtQyxRQUFTLFdBQ1R0QyxZQUNFLHNFQUVKcUUsTUFBTyxDQUNMdkUsTUFBTyxJQUNQQyxLQUFNLFNBQ05JLFFBQVMsV0FDVG1DLFFBQVMsVUFDVHRDLFlBQ0UsNEVBR05zRSxNQUFPLENBQ0xDLFFBQVMsQ0FDUHpFLE1BQU8sYUFDUEMsS0FBTSxTQUNOSSxRQUFTLGlCQUNUSCxZQUFhLG9DQUVmd0UscUJBQXNCLENBQ3BCMUUsT0FBTyxFQUNQQyxLQUFNLFVBQ05JLFFBQVMsZ0NBQ1RILFlBQWEsMkRBRWZ5RSxPQUFRLENBQ04zRSxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxnQkFDVEgsWUFDRSwyRUFFSjBFLGNBQWUsQ0FDYjVFLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLHdCQUNUSCxZQUFhLDBEQUdqQjJFLE1BQU8sQ0FDTHRDLE9BQVEsQ0FDTnZDLE9BQU8sRUFDUEMsS0FBTSxVQUNOSSxRQUFTLGVBQ1RtQyxRQUFTLGNBQ1R0QyxZQUFhLDhEQUVmNEUsU0FBVSxDQUNSOUUsT0FBTyxFQUNQQyxLQUFNLFVBQ05JLFFBQVMsaUJBQ1RILFlBQ0UsOEVBRUo2RSxTQUFVLENBQ1IvRSxPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxpQkFDVEgsWUFDRSw4RUFFSjhFLGdCQUFpQixDQUNmaEYsT0FBTyxFQUNQQyxLQUFNLFVBQ05JLFFBQVMsMEJBQ1RILFlBQ0Usb0ZBRUorRSxPQUFRLENBQ05qRixPQUFPLEVBQ1BDLEtBQU0sVUFDTkksUUFBUyxlQUNUSCxZQUNFLHFGQUVKZ0YsT0FBUSxDQUNObEYsTUFBTyxFQUNQQyxLQUFNLFNBQ05JLFFBQVMsZ0JBQ1RILFlBQ0UsNEVBRUppRixjQUFlLENBQ2JuRixNQUFPLEtBQ1BDLEtBQU0sU0FDTkksUUFBUyx1QkFDVEgsWUFBYSxtQ0FXTmtGLEVBQWdCLENBQzNCdEYsVUFBVyxDQUNULENBQ0VHLEtBQU0sT0FDTm9GLEtBQU0sT0FDTkMsUUFBUyxzQkFDVEMsUUFBUzFGLEVBQWNDLFVBQVVDLEtBQUtDLE1BQU13RixLQUFLLEtBQ2pEQyxVQUFXLE1BR2Z0RixXQUFZLENBQ1YsQ0FDRUYsS0FBTSxPQUNOb0YsS0FBTSxVQUNOQyxRQUFTLHFCQUNUQyxRQUFTMUYsRUFBY00sV0FBV0MsUUFBUUosT0FFNUMsQ0FDRUMsS0FBTSxPQUNOb0YsS0FBTSxTQUNOQyxRQUFTLGlCQUNUQyxRQUFTMUYsRUFBY00sV0FBV0csT0FBT04sT0FFM0MsQ0FDRUMsS0FBTSxjQUNOb0YsS0FBTSxjQUNOQyxRQUFTLHlCQUNUSSxhQUFjLHlEQUNkQyxRQUFTOUYsRUFBY00sV0FBV0ksWUFBWVAsT0FFaEQsQ0FDRUMsS0FBTSxjQUNOb0YsS0FBTSxnQkFDTkMsUUFBUywyQkFDVEksYUFBYyx5REFDZEMsUUFBUzlGLEVBQWNNLFdBQVdLLGNBQWNSLE9BRWxELENBQ0VDLEtBQU0sY0FDTm9GLEtBQU0sbUJBQ05DLFFBQVMsOEJBQ1RJLGFBQWMseURBQ2RDLFFBQVM5RixFQUFjTSxXQUFXTSxpQkFBaUJULE9BRXJELENBQ0VDLEtBQU0sT0FDTm9GLEtBQU0sZ0JBQ05DLFFBQVMsaUJBQ1RDLFFBQVMxRixFQUFjTSxXQUFXTyxjQUFjVixNQUFNd0YsS0FBSyxLQUMzREMsVUFBVyxLQUViLENBQ0V4RixLQUFNLFNBQ05vRixLQUFNLGFBQ05DLFFBQVMsNkJBQ1RDLFFBQVMxRixFQUFjTSxXQUFXUSxXQUFXWCxPQUUvQyxDQUNFQyxLQUFNLE9BQ05vRixLQUFNLFlBQ05DLFFBQVMsa0NBQ1RDLFFBQVMxRixFQUFjTSxXQUFXUyxVQUFVWixRQUdoRGEsT0FBUSxDQUNOLENBQ0VaLEtBQU0sU0FDTm9GLEtBQU0sT0FDTkMsUUFBUywrQkFDVE0sS0FBTSxZQUFZL0YsRUFBY2dCLE9BQU9aLEtBQUtELFFBQzVDdUYsUUFBUyxFQUNUSSxRQUFTLENBQUMsTUFBTyxPQUFRLE1BQU8sUUFFbEMsQ0FDRTFGLEtBQU0sU0FDTm9GLEtBQU0sU0FDTkMsUUFBUyx5Q0FDVE0sS0FBTSxZQUFZL0YsRUFBY2dCLE9BQU9LLE9BQU9sQixRQUM5Q3VGLFFBQVMsRUFDVEksUUFBUyxDQUFDLFFBQVMsYUFBYyxXQUFZLGVBRS9DLENBQ0UxRixLQUFNLFNBQ05vRixLQUFNLGdCQUNOQyxRQUFTLG9EQUNUQyxRQUFTMUYsRUFBY2dCLE9BQU9NLGNBQWNuQixPQUU5QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLGVBQ05DLFFBQVMsbURBQ1RDLFFBQVMxRixFQUFjZ0IsT0FBT08sYUFBYXBCLE9BRTdDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sZUFDTkMsUUFBUyxtREFDVEMsUUFBUzFGLEVBQWNnQixPQUFPUSxhQUFhckIsTUFDM0M2RixJQUFLLEdBQ0xDLElBQUssR0FFUCxDQUNFN0YsS0FBTSxTQUNOb0YsS0FBTSx1QkFDTkMsUUFBUyxnREFDVEMsUUFBUzFGLEVBQWNnQixPQUFPZSxxQkFBcUI1QixRQUd2RDZCLFlBQWEsQ0FDWCxDQUNFNUIsS0FBTSxTQUNOb0YsS0FBTSxxQkFDTkMsUUFBUyxrQ0FDVEMsUUFBUzFGLEVBQWNnQyxZQUFZQyxtQkFBbUI5QixPQUV4RCxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLHFCQUNOQyxRQUFTLHdCQUNUQyxRQUFTMUYsRUFBY2dDLFlBQVlFLG1CQUFtQi9CLFFBRzFEc0MsT0FBUSxDQUNOLENBQ0VyQyxLQUFNLFNBQ05vRixLQUFNLFNBQ05DLFFBQVMsK0JBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT0MsT0FBT3ZDLE9BRXZDLENBQ0VDLEtBQU0sT0FDTm9GLEtBQU0sT0FDTkMsUUFBUyxrQkFDVEMsUUFBUzFGLEVBQWN5QyxPQUFPRyxLQUFLekMsT0FFckMsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxPQUNOQyxRQUFTLGNBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT0ksS0FBSzFDLE9BRXJDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sZUFDTkMsUUFBUyw2QkFDVEMsUUFBUzFGLEVBQWN5QyxPQUFPSyxhQUFhM0MsT0FFN0MsQ0FDRUMsS0FBTSxPQUNOb0YsS0FBTSxhQUNOQyxRQUFTLHNDQUNUQyxRQUFTMUYsRUFBY3lDLE9BQU9NLE1BQU1ILEtBQUt6QyxPQUUzQyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLGFBQ05DLFFBQVMsc0NBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT00sTUFBTUYsS0FBSzFDLE9BRTNDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sZ0JBQ05DLFFBQVMsMENBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT00sTUFBTUMsUUFBUTdDLE9BRTlDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sc0JBQ05DLFFBQVMsdUJBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYVAsT0FBT3ZDLE9BRXBELENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sMkJBQ05DLFFBQVMsMENBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYUMsWUFBWS9DLE9BRXpELENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sc0JBQ05DLFFBQVMsMkNBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYUUsT0FBT2hELE9BRXBELENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0scUJBQ05DLFFBQ0Usb0VBQ0ZDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYUcsTUFBTWpELE9BRW5ELENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sMEJBQ05DLFFBQVMsd0NBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYUksV0FBV2xELE9BRXhELENBQ0VDLEtBQU0sT0FDTm9GLEtBQU0sdUJBQ05DLFFBQ0UsOEVBQ0ZDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYUssUUFBUW5ELE9BRXJELENBQ0VDLEtBQU0sT0FDTm9GLEtBQU0seUJBQ05DLFFBQ0UsNEVBQ0ZDLFFBQVMxRixFQUFjeUMsT0FBT1EsYUFBYU0sVUFBVXBELE9BRXZELENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sYUFDTkMsUUFBUyxzQkFDVEMsUUFBUzFGLEVBQWN5QyxPQUFPZSxJQUFJZCxPQUFPdkMsT0FFM0MsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxZQUNOQyxRQUFTLGdDQUNUQyxRQUFTMUYsRUFBY3lDLE9BQU9lLElBQUlDLE1BQU10RCxPQUUxQyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLFdBQ05DLFFBQVMsa0JBQ1RDLFFBQVMxRixFQUFjeUMsT0FBT2UsSUFBSVgsS0FBSzFDLE9BRXpDLENBQ0VDLEtBQU0sT0FDTm9GLEtBQU0sZUFDTkMsUUFBUywyQ0FDVEMsUUFBUzFGLEVBQWN5QyxPQUFPZSxJQUFJRSxTQUFTdkQsUUFHL0N3RCxLQUFNLENBQ0osQ0FDRXZELEtBQU0sU0FDTm9GLEtBQU0sYUFDTkMsUUFBUyx5Q0FDVEMsUUFBUzFGLEVBQWMyRCxLQUFLQyxXQUFXekQsT0FFekMsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxhQUNOQyxRQUFTLHlDQUNUQyxRQUFTMUYsRUFBYzJELEtBQUtFLFdBQVcxRCxPQUV6QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLFlBQ05DLFFBQ0UsaUZBQ0ZDLFFBQVMxRixFQUFjMkQsS0FBS0csVUFBVTNELE9BRXhDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0saUJBQ05DLFFBQVMsOERBQ1RDLFFBQVMxRixFQUFjMkQsS0FBS0ksZUFBZTVELE9BRTdDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sZ0JBQ05DLFFBQVMsNkRBQ1RDLFFBQVMxRixFQUFjMkQsS0FBS0ssY0FBYzdELE9BRTVDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0saUJBQ05DLFFBQVMsK0RBQ1RDLFFBQVMxRixFQUFjMkQsS0FBS00sZUFBZTlELE9BRTdDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sY0FDTkMsUUFBUyxpRUFDVEMsUUFBUzFGLEVBQWMyRCxLQUFLTyxZQUFZL0QsT0FFMUMsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxzQkFDTkMsUUFDRSxrRUFDRkMsUUFBUzFGLEVBQWMyRCxLQUFLUSxvQkFBb0JoRSxPQUVsRCxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLGlCQUNOQyxRQUNFLCtGQUNGQyxRQUFTMUYsRUFBYzJELEtBQUtTLGVBQWVqRSxPQUU3QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLGVBQ05DLFFBQVMsMENBQ1RDLFFBQVMxRixFQUFjMkQsS0FBS2IsYUFBYTNDLFFBRzdDa0UsUUFBUyxDQUNQLENBQ0VqRSxLQUFNLFNBQ05vRixLQUFNLFFBQ05DLFFBQ0UsdUZBQ0ZDLFFBQVMxRixFQUFjcUUsUUFBUUMsTUFBTW5FLE1BQ3JDK0YsTUFBTyxFQUNQRixJQUFLLEVBQ0xDLElBQUssR0FFUCxDQUNFN0YsS0FBTSxPQUNOb0YsS0FBTSxPQUNOQyxRQUFTLGlFQUNUQyxRQUFTMUYsRUFBY3FFLFFBQVFFLEtBQUtwRSxPQUV0QyxDQUNFQyxLQUFNLE9BQ05vRixLQUFNLE9BQ05DLFFBQVMsOENBQ1RDLFFBQVMxRixFQUFjcUUsUUFBUUcsS0FBS3JFLFFBR3hDc0UsR0FBSSxDQUNGLENBQ0VyRSxLQUFNLFNBQ05vRixLQUFNLFNBQ05DLFFBQVMsa0NBQ1RDLFFBQVMxRixFQUFjeUUsR0FBRy9CLE9BQU92QyxPQUVuQyxDQUNFQyxLQUFNLE9BQ05vRixLQUFNLFFBQ05DLFFBQVMsMkJBQ1RDLFFBQVMxRixFQUFjeUUsR0FBR0MsTUFBTXZFLFFBR3BDd0UsTUFBTyxDQUNMLENBQ0V2RSxLQUFNLE9BQ05vRixLQUFNLFVBQ05DLFFBQVMsa0NBQ1RDLFFBQVMxRixFQUFjMkUsTUFBTUMsUUFBUXpFLE9BRXZDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sdUJBQ05DLFFBQVMsdURBQ1RDLFFBQVMxRixFQUFjMkUsTUFBTUUscUJBQXFCMUUsT0FFcEQsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxTQUNOQyxRQUFTLDZEQUNUQyxRQUFTMUYsRUFBYzJFLE1BQU1HLE9BQU8zRSxPQUV0QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLGdCQUNOQyxRQUFTLHVEQUNUQyxRQUFTMUYsRUFBYzJFLE1BQU1JLGNBQWM1RSxRQUcvQzZFLE1BQU8sQ0FDTCxDQUNFNUUsS0FBTSxTQUNOb0YsS0FBTSxTQUNOQyxRQUFTLDhDQUNUQyxRQUFTMUYsRUFBY2dGLE1BQU10QyxPQUFPdkMsT0FFdEMsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxXQUNOQyxRQUFTLG1DQUNUQyxRQUFTMUYsRUFBY2dGLE1BQU1DLFNBQVM5RSxPQUV4QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLFdBQ05DLFFBQVMsdUNBQ1RDLFFBQVMxRixFQUFjZ0YsTUFBTUUsU0FBUy9FLE9BRXhDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sa0JBQ05DLFFBQVMsMkRBQ1RDLFFBQVMxRixFQUFjZ0YsTUFBTUcsZ0JBQWdCaEYsT0FFL0MsQ0FDRUMsS0FBTSxTQUNOb0YsS0FBTSxTQUNOQyxRQUFTLDREQUNUQyxRQUFTMUYsRUFBY2dGLE1BQU1JLE9BQU9qRixPQUV0QyxDQUNFQyxLQUFNLFNBQ05vRixLQUFNLFNBQ05DLFFBQVMsaURBQ1RDLFFBQVMxRixFQUFjZ0YsTUFBTUssT0FBT2xGLE9BRXRDLENBQ0VDLEtBQU0sU0FDTm9GLEtBQU0sZ0JBQ05DLFFBQVMsZ0NBQ1RDLFFBQVMxRixFQUFjZ0YsTUFBTU0sY0FBY25GLFNBTXBDZ0csRUFBZ0IsQ0FDM0IsVUFDQSxnQkFDQSxlQUNBLFlBQ0EsV0FJV0MsRUFBYSxDQUFBLEVBU3BCQyxFQUFtQixDQUFDQyxFQUFLQyxFQUFZLE1BQ3pDQyxPQUFPQyxLQUFLSCxHQUFLSSxTQUFTQyxJQUN4QixJQUFLLENBQUMsWUFBYSxjQUFjQyxTQUFTRCxHQUFJLENBQzVDLE1BQU1FLEVBQVFQLEVBQUlLLFFBQ1MsSUFBaEJFLEVBQU0xRyxNQUVma0csRUFBaUJRLEVBQU8sR0FBR04sS0FBYUksTUFHeENQLEVBQVdTLEVBQU1sRSxTQUFXZ0UsR0FBSyxHQUFHSixLQUFhSSxJQUFJRyxVQUFVLFFBR3RDQyxJQUFyQkYsRUFBTXRFLGFBQ1I2RCxFQUFXUyxFQUFNdEUsWUFBYyxHQUFHZ0UsS0FBYUksSUFBSUcsVUFBVSxJQUdsRSxJQUNELEVBR0pULEVBQWlCckcsR0N2bENqQmdILEVBQU9DLFNBSVAsTUFBTUMsRUFHSUMsR0FDTkMsRUFBQ0EsRUFDRUMsU0FDQUMsV0FBV25ILEdBQ1ZBLEVBQ0dvSCxNQUFNLEtBQ05DLEtBQUtySCxHQUFVQSxFQUFNc0gsU0FDckJDLFFBQVF2SCxHQUFVZ0gsRUFBWVAsU0FBU3pHLE9BRTNDbUgsV0FBV25ILEdBQVdBLEVBQU13SCxPQUFTeEgsT0FBUTRHLElBWjlDRyxFQWdCSyxJQUNQRSxFQUFDQSxFQUNFUSxLQUFLLENBQUMsT0FBUSxRQUFTLEtBQ3ZCTixXQUFXbkgsR0FBcUIsS0FBVkEsRUFBeUIsU0FBVkEsT0FBbUI0RyxJQW5CekRHLEVBdUJHVyxHQUNMVCxFQUFDQSxFQUNFUSxLQUFLLElBQUlDLEVBQVEsS0FDakJQLFdBQVduSCxHQUFxQixLQUFWQSxFQUFlQSxPQUFRNEcsSUExQjlDRyxFQThCSSxJQUNORSxFQUFDQSxFQUNFQyxTQUNBSSxPQUNBSyxRQUNFM0gsSUFDRSxDQUFDLFFBQVMsWUFBYSxPQUFRLE9BQU95RyxTQUFTekcsSUFDdEMsS0FBVkEsSUFDREEsSUFBVyxDQUNWc0YsUUFBUyxtREFBbUR0RixTQUcvRG1ILFdBQVduSCxHQUFxQixLQUFWQSxFQUFlQSxPQUFRNEcsSUExQzlDRyxFQThDUyxJQUNYRSxFQUFDQSxFQUNFQyxTQUNBSSxPQUNBSyxRQUNFM0gsR0FDVyxLQUFWQSxJQUFrQjRILE1BQU1DLFdBQVc3SCxLQUFXNkgsV0FBVzdILEdBQVMsSUFDbkVBLElBQVcsQ0FDVnNGLFFBQVMscURBQXFEdEYsU0FHakVtSCxXQUFXbkgsR0FBcUIsS0FBVkEsRUFBZTZILFdBQVc3SCxRQUFTNEcsSUF6RDFERyxFQTZEWSxJQUNkRSxFQUFDQSxFQUNFQyxTQUNBSSxPQUNBSyxRQUNFM0gsR0FDVyxLQUFWQSxJQUFrQjRILE1BQU1DLFdBQVc3SCxLQUFXNkgsV0FBVzdILElBQVUsSUFDcEVBLElBQVcsQ0FDVnNGLFFBQVMseURBQXlEdEYsU0FHckVtSCxXQUFXbkgsR0FBcUIsS0FBVkEsRUFBZTZILFdBQVc3SCxRQUFTNEcsSUEySG5Ea0IsRUF4SFNiLEVBQUNBLEVBQUNjLE9BQU8sQ0FFN0JDLG1CQUFvQmYsRUFBQ0EsRUFDbEJDLFNBQ0FJLE9BQ0FLLFFBQ0UzSCxHQUFVLDZCQUE2QmlJLEtBQUtqSSxJQUFvQixLQUFWQSxJQUN0REEsSUFBVyxDQUNWc0YsUUFBUyw0RkFBNEZ0RixTQUd4R21ILFdBQVduSCxHQUFxQixLQUFWQSxFQUFlQSxPQUFRNEcsSUFDaERzQixtQkFBb0JqQixFQUFDQSxFQUNsQkMsU0FDQUksT0FDQUssUUFDRTNILEdBQ0NBLEVBQU1tSSxXQUFXLGFBQ2pCbkksRUFBTW1JLFdBQVcsWUFDUCxLQUFWbkksSUFDREEsSUFBVyxDQUNWc0YsUUFBUyw2RkFBNkZ0RixTQUd6R21ILFdBQVduSCxHQUFxQixLQUFWQSxFQUFlQSxPQUFRNEcsSUFDaER3Qix3QkFBeUJyQixFQUFRdEgsRUFBYUMsTUFDOUMySSwwQkFBMkJ0QixFQUFRdEgsRUFBYUUsU0FDaEQySSw2QkFBOEJ2QixFQUFRdEgsRUFBYUcsWUFDbkQySSx1QkFBd0J4QixJQUN4QnlCLHNCQUF1QnpCLElBQ3ZCMEIsdUJBQXdCMUIsSUFHeEIyQixZQUFhM0IsRUFBTyxDQUFDLE9BQVEsTUFBTyxNQUFPLFFBQzNDNEIsY0FBZTVCLEVBQU8sQ0FBQyxRQUFTLGFBQWMsV0FBWSxlQUMxRDZCLHNCQUF1QjdCLElBQ3ZCOEIscUJBQXNCOUIsSUFDdEIrQixxQkFBc0IvQixJQUN0QmdDLDZCQUE4QmhDLElBRzlCaUMsa0NBQW1DakMsSUFDbkNrQyxrQ0FBbUNsQyxJQUduQ21DLGNBQWVuQyxJQUNmb0MsWUFBYXBDLElBQ2JxQyxZQUFhckMsSUFDYnNDLG9CQUFxQnRDLElBR3JCdUMsa0JBQW1CdkMsSUFDbkJ3QyxrQkFBbUJ4QyxJQUNuQnlDLHFCQUFzQnpDLElBR3RCMEMsNEJBQTZCMUMsSUFDN0IyQyxrQ0FBbUMzQyxJQUNuQzRDLDRCQUE2QjVDLElBQzdCNkMsMkJBQTRCN0MsSUFDNUI4QyxpQ0FBa0M5QyxJQUNsQytDLDhCQUErQi9DLElBQy9CZ0QsZ0NBQWlDaEQsSUFHakNpRCxrQkFBbUJqRCxJQUNuQmtELGlCQUFrQmxELElBQ2xCbUQsZ0JBQWlCbkQsSUFDakJvRCxxQkFBc0JwRCxJQUd0QnFELGlCQUFrQnJELElBQ2xCc0QsaUJBQWtCdEQsSUFDbEJ1RCxnQkFBaUJ2RCxJQUNqQndELHFCQUFzQnhELElBQ3RCeUQsb0JBQXFCekQsSUFDckIwRCxxQkFBc0IxRCxJQUN0QjJELGtCQUFtQjNELElBQ25CNEQsMkJBQTRCNUQsSUFDNUI2RCxxQkFBc0I3RCxJQUN0QjhELGtCQUFtQjlELElBR25CK0QsY0FBZTdELEVBQUNBLEVBQ2JDLFNBQ0FJLE9BQ0FLLFFBQ0UzSCxHQUNXLEtBQVZBLElBQ0U0SCxNQUFNQyxXQUFXN0gsS0FDakI2SCxXQUFXN0gsSUFBVSxHQUNyQjZILFdBQVc3SCxJQUFVLElBQ3hCQSxJQUFXLENBQ1ZzRixRQUFTLG1HQUFtR3RGLFNBRy9HbUgsV0FBV25ILEdBQXFCLEtBQVZBLEVBQWU2SCxXQUFXN0gsUUFBUzRHLElBQzVEbUUsYUFBY2hFLElBQ2RpRSxhQUFjakUsSUFHZGtFLFVBQVdsRSxJQUNYbUUsU0FBVW5FLElBR1ZvRSxlQUFnQnBFLEVBQU8sQ0FBQyxjQUFlLGFBQWMsU0FDckRxRSw4QkFBK0JyRSxJQUMvQnNFLGNBQWV0RSxJQUNmdUUsc0JBQXVCdkUsSUFHdkJ3RSxhQUFjeEUsSUFDZHlFLGVBQWdCekUsSUFDaEIwRSxlQUFnQjFFLElBQ2hCMkUsd0JBQXlCM0UsSUFDekI0RSxhQUFjNUUsSUFDZDZFLGNBQWU3RSxJQUNmOEUscUJBQXNCOUUsTUFHRytFLFVBQVVDLE1BQU1DLFFBQVFDLEtDdE03Q0MsRUFBUyxDQUFDLE1BQU8sU0FBVSxPQUFRLE9BQVEsU0FHakQsSUFBSWhJLEVBQVUsQ0FFWmlJLFdBQVcsRUFDWEMsUUFBUSxFQUNSQyxhQUFhLEVBRWJDLFdBQVksQ0FDVixDQUNFQyxNQUFPLFFBQ1BDLE1BQU9OLEVBQU8sSUFFaEIsQ0FDRUssTUFBTyxVQUNQQyxNQUFPTixFQUFPLElBRWhCLENBQ0VLLE1BQU8sU0FDUEMsTUFBT04sRUFBTyxJQUVoQixDQUNFSyxNQUFPLFVBQ1BDLE1BQU9OLEVBQU8sSUFFaEIsQ0FDRUssTUFBTyxZQUNQQyxNQUFPTixFQUFPLEtBSWxCTyxVQUFXLElBSWIsSUFBSyxNQUFPQyxFQUFLQyxLQUFXdEcsT0FBT3VHLFFBQVEvTSxFQUFjcUUsU0FDdkRBLEVBQVF3SSxHQUFPQyxFQUFPM00sTUFXeEIsTUFBTTZNLEVBQVksQ0FBQ0MsRUFBT0MsS0FDcEI3SSxFQUFRa0ksU0FDTGxJLEVBQVFtSSxlQUVWVyxFQUFBQSxXQUFXOUksRUFBUUcsT0FBUzRJLEVBQUFBLFVBQVUvSSxFQUFRRyxNQUkvQ0gsRUFBUW1JLGFBQWMsR0FJeEJhLEVBQVVBLFdBQ1IsR0FBR2hKLEVBQVFHLE9BQU9ILEVBQVFFLE9BQzFCLENBQUMySSxHQUFRSSxPQUFPTCxHQUFPdEgsS0FBSyxLQUFPLE1BQ2xDNEgsSUFDS0EsSUFDRkMsUUFBUUMsSUFBSSx5Q0FBeUNGLEtBQ3JEbEosRUFBUWtJLFFBQVMsRUFDbEIsSUFHTixFQVdVa0IsRUFBTSxJQUFJdk4sS0FDckIsTUFBT3dOLEtBQWFULEdBQVMvTSxHQUd2Qm9FLE1BQUVBLEVBQUttSSxXQUFFQSxHQUFlcEksRUFHOUIsR0FDZSxJQUFicUosSUFDYyxJQUFiQSxHQUFrQkEsRUFBV3BKLEdBQVNBLEVBQVFtSSxFQUFXOUUsUUFFMUQsT0FJRixNQUdNdUYsRUFBUyxJQUhDLElBQUlTLE1BQU9DLFdBQVdyRyxNQUFNLEtBQUssR0FBR0UsV0FHdEJnRixFQUFXaUIsRUFBVyxHQUFHaEIsV0FHdkRySSxFQUFRdUksVUFBVWxHLFNBQVNtSCxJQUN6QkEsRUFBR1gsRUFBUUQsRUFBTXRILEtBQUssS0FBSyxJQUl6QnRCLEVBQVFpSSxXQUNWa0IsUUFBUUMsSUFBSUssV0FDVi9HLEVBQ0EsQ0FBQ21HLEVBQU9VLFdBQVd2SixFQUFRb0ksV0FBV2lCLEVBQVcsR0FBR2YsUUFBUVcsT0FBT0wsSUFLdkVELEVBQVVDLEVBQU9DLEVBQU8sRUFZYmEsRUFBZSxDQUFDTCxFQUFVSCxFQUFPUyxLQUU1QyxNQUFNQyxFQUFjRCxHQUFpQlQsRUFBTTlILFNBR3JDbkIsTUFBRUEsRUFBS21JLFdBQUVBLEdBQWVwSSxFQUc5QixHQUFpQixJQUFicUosR0FBa0JBLEVBQVdwSixHQUFTQSxFQUFRbUksRUFBVzlFLE9BQzNELE9BSUYsTUFHTXVGLEVBQVMsSUFIQyxJQUFJUyxNQUFPQyxXQUFXckcsTUFBTSxLQUFLLEdBQUdFLFdBR3RCZ0YsRUFBV2lCLEVBQVcsR0FBR2hCLFdBR2pEd0IsRUFDSlgsRUFBTTlILFVBQVk4SCxFQUFNVyxtQkFBdUNuSCxJQUF2QndHLEVBQU1XLGFBQzFDWCxFQUFNWSxNQUNOWixFQUFNWSxNQUFNNUcsTUFBTSxNQUFNNkcsTUFBTSxHQUFHekksS0FBSyxNQUd0Q3NILEVBQVEsQ0FBQ2dCLEVBQWEsS0FBTUMsR0FHOUI3SixFQUFRaUksV0FDVmtCLFFBQVFDLElBQUlLLFdBQ1YvRyxFQUNBLENBQUNtRyxFQUFPVSxXQUFXdkosRUFBUW9JLFdBQVdpQixFQUFXLEdBQUdmLFFBQVFXLE9BQU8sQ0FDakVXLEVBQVk1QixFQUFPcUIsRUFBVyxJQUM5QixLQUNBUSxLQU1ON0osRUFBUXVJLFVBQVVsRyxTQUFTbUgsSUFDekJBLEVBQUdYLEVBQVFELEVBQU10SCxLQUFLLEtBQUssSUFJN0JxSCxFQUFVQyxFQUFPQyxFQUFPLEVBU2JtQixFQUFlWCxJQUN0QkEsR0FBWSxHQUFLQSxHQUFZckosRUFBUW9JLFdBQVc5RSxTQUNsRHRELEVBQVFDLE1BQVFvSixFQUNqQixFQVNVWSxFQUFvQixDQUFDQyxFQUFTQyxLQVN6QyxHQVBBbkssRUFBVSxJQUNMQSxFQUNIRyxLQUFNK0osR0FBV2xLLEVBQVFHLEtBQ3pCRCxLQUFNaUssR0FBV25LLEVBQVFFLEtBQ3pCZ0ksUUFBUSxHQUdrQixJQUF4QmxJLEVBQVFHLEtBQUttRCxPQUNmLE9BQU84RixFQUFJLEVBQUcsMkRBR1hwSixFQUFRRyxLQUFLaUssU0FBUyxPQUN6QnBLLEVBQVFHLE1BQVEsSUFDakIsRUM1TVVrSyxFQUFZQyxFQUFhQSxjQUFDLElBQUlDLElBQUksT0FBUSxvQkFBQUMsU0FBQUMsUUFBQSxPQUFBQyxjQUFBQyxZQUFBQyxLQUFBQyxHQUFBQSxFQUFBQyxLQUFBLElBQUFQLElBQUEsWUFBQUMsU0FBQU8sU0FBQUgsT0FpRTFDSSxFQUFVLENBQUNqUCxFQUFNZ0IsS0FFNUIsTUFRTWtPLEVBQVUsQ0FBQyxNQUFPLE9BQVEsTUFBTyxPQUd2QyxHQUFJbE8sRUFBUyxDQUNYLE1BQU1tTyxFQUFVbk8sRUFBUW1HLE1BQU0sS0FBS2lJLE1BRW5CLFFBQVpELEVBQ0ZuUCxFQUFPLE9BQ0VrUCxFQUFRMUksU0FBUzJJLElBQVluUCxJQUFTbVAsSUFDL0NuUCxFQUFPbVAsRUFFVixDQUdELE1BdEJrQixDQUNoQixZQUFhLE1BQ2IsYUFBYyxPQUNkLGtCQUFtQixNQUNuQixnQkFBaUIsT0FrQkZuUCxJQUFTa1AsRUFBUUcsTUFBTUMsR0FBTUEsSUFBTXRQLEtBQVMsS0FBSyxFQWN2RHVQLEVBQWtCLENBQUN0TixHQUFZLEVBQU9ILEtBQ2pELE1BQU0wTixFQUFlLENBQUMsS0FBTSxNQUFPLFNBRW5DLElBQUlDLEVBQW1CeE4sRUFDbkJ5TixHQUFtQixFQUd2QixHQUFJNU4sR0FBc0JHLEVBQVVvTSxTQUFTLFNBQzNDLElBQ0VvQixFQUFtQkUsRUFBY0MsRUFBQUEsYUFBYTNOLEVBQVcsUUFDMUQsQ0FBQyxNQUFPa0wsR0FDUCxPQUFPUSxFQUFhLEVBQUdSLEVBQU8sNEJBQy9CLE1BR0RzQyxFQUFtQkUsRUFBYzFOLEdBRzdCd04sSUFBcUIzTixVQUNoQjJOLEVBQWlCSSxNQUs1QixJQUFLLE1BQU1DLEtBQVlMLEVBQ2hCRCxFQUFhaEosU0FBU3NKLEdBRWZKLElBQ1ZBLEdBQW1CLFVBRlpELEVBQWlCSyxHQU81QixPQUFLSixHQUtERCxFQUFpQkksUUFDbkJKLEVBQWlCSSxNQUFRSixFQUFpQkksTUFBTXpJLEtBQUsySSxHQUFTQSxFQUFLMUksV0FDOURvSSxFQUFpQkksT0FBU0osRUFBaUJJLE1BQU10SSxRQUFVLFdBQ3ZEa0ksRUFBaUJJLE9BS3JCSixHQVpFcEMsRUFBSSxFQUFHLDRCQVlPLEVBY2xCLFNBQVNzQyxFQUFjSyxFQUFNeEMsR0FDbEMsSUFFRSxNQUFNeUMsRUFBYUMsS0FBS3BFLE1BQ04saUJBQVRrRSxFQUFvQkUsS0FBS0MsVUFBVUgsR0FBUUEsR0FJcEQsTUFBMEIsaUJBQWZDLEdBQTJCekMsRUFDN0IwQyxLQUFLQyxVQUFVRixHQUlqQkEsQ0FDWCxDQUFJLE1BQ0EsT0FBTyxDQUNSLENBQ0gsQ0FTTyxNQTJDTUcsRUFBWWxLLElBQ3ZCLEdBQVksT0FBUkEsR0FBK0IsaUJBQVJBLEVBQ3pCLE9BQU9BLEVBR1QsTUFBTW1LLEVBQU9DLE1BQU1DLFFBQVFySyxHQUFPLEdBQUssR0FFdkMsSUFBSyxNQUFNdUcsS0FBT3ZHLEVBQ1pFLE9BQU9vSyxVQUFVQyxlQUFlQyxLQUFLeEssRUFBS3VHLEtBQzVDNEQsRUFBSzVELEdBQU8yRCxFQUFTbEssRUFBSXVHLEtBSTdCLE9BQU80RCxDQUFJLEVBYUFNLEVBQW1CLENBQUM1UCxFQUFTNlAsSUFzQmpDVixLQUFLQyxVQUFVcFAsR0FyQkcsQ0FBQ3FFLEVBQU1yRixLQUNULGlCQUFWQSxLQUNUQSxFQUFRQSxFQUFNc0gsUUFJTGEsV0FBVyxjQUFnQm5JLEVBQU1tSSxXQUFXLGdCQUNuRG5JLEVBQU1zTyxTQUFTLE9BRWZ0TyxFQUFRNlEsRUFDSixXQUFXN1EsRUFBUSxJQUFJOFEsV0FBVyxZQUFhLG1CQUMvQ2xLLEdBSWdCLG1CQUFWNUcsRUFDVixXQUFXQSxFQUFRLElBQUk4USxXQUFXLFlBQWEsY0FDL0M5USxLQUkyQzhRLFdBQy9DLHFCQUNBLElBaUNHLFNBQVNDLElBS2QxRCxRQUFRQyxJQUNOLDRCQUE0QjBELEtBQzVCLFdBQ0EseURBTmEsMERBTW1EQSxLQUFLQyxXQUd2RSxNQUFNQyxFQUFtQmxRLElBQ3ZCLElBQUssTUFBT3FFLEVBQU1zSCxLQUFXdEcsT0FBT3VHLFFBQVE1TCxHQUUxQyxHQUFLcUYsT0FBT29LLFVBQVVDLGVBQWVDLEtBQUtoRSxFQUFRLFNBRTNDLENBQ0wsSUFBSXdFLEVBQVcsT0FBT3hFLEVBQU9uSyxTQUFXNkMsTUFDckMsSUFBTXNILEVBQU8xTSxLQUFPLEtBQUttUixTQUU1QixHQUFJRCxFQUFTM0osT0FuQlAsR0FvQkosSUFBSyxJQUFJNkosRUFBSUYsRUFBUzNKLE9BQVE2SixFQXBCMUIsR0FvQm1DQSxJQUNyQ0YsR0FBWSxJQUtoQjlELFFBQVFDLElBQ042RCxFQUNBeEUsRUFBT3pNLFlBQ1AsYUFBYXlNLEVBQU8zTSxNQUFNeU4sV0FBV3VELFFBQVFNLEtBRWhELE1BakJDSixFQUFnQnZFLEVBa0JuQixFQUlIdEcsT0FBT0MsS0FBS3pHLEdBQWUwRyxTQUFTZ0wsSUFFN0IsQ0FBQyxZQUFhLGNBQWM5SyxTQUFTOEssS0FDeENsRSxRQUFRQyxJQUFJLEtBQUtpRSxFQUFTQyxnQkFBZ0JDLEtBQzFDUCxFQUFnQnJSLEVBQWMwUixJQUMvQixJQUVIbEUsUUFBUUMsSUFBSSxLQUNkLENBVU8sTUFZTW9FLEVBQWExQixJQUN4QixDQUFDLFFBQVMsWUFBYSxPQUFRLE1BQU8sSUFBSyxJQUFJdkosU0FBU3VKLE1BRWxEQSxFQVdLMkIsRUFBYSxDQUFDM1AsRUFBWUQsS0FDckMsR0FBSUMsR0FBb0MsaUJBQWZBLEVBR3ZCLE9BRkFBLEVBQWFBLEVBQVdzRixRQUVUZ0gsU0FBUyxTQUNmdk0sR0FDSDRQLEVBQVc5QixFQUFZQSxhQUFDN04sRUFBWSxTQUd4Q0EsRUFBV21HLFdBQVcsZUFDdEJuRyxFQUFXbUcsV0FBVyxnQkFDdEJuRyxFQUFXbUcsV0FBVyxTQUN0Qm5HLEVBQVdtRyxXQUFXLFNBRWYsSUFBSW5HLE9BRU5BLEVBQVc0UCxRQUFRLEtBQU0sR0FDakMsRUFTVUMsRUFBYyxLQUN6QixNQUFNQyxFQUFROUYsUUFBUStGLE9BQU9DLFNBQzdCLE1BQU8sSUFBTUMsT0FBT2pHLFFBQVErRixPQUFPQyxTQUFXRixHQUFTLEdBQU8sRUNuYWhFLElBQUlJLEVBQWlCLENBQUEsRUFPZCxNQUFNQyxFQUFhLElBQU1ELEVBZ0xuQkUsRUFBcUIsQ0FBQ3BSLEVBQVNxUixFQUFZck0sRUFBZ0IsTUFDdEUsTUFBTXNNLEVBQWdCakMsRUFBU3JQLEdBRS9CLElBQUssTUFBTzBMLEVBQUsxTSxLQUFVcUcsT0FBT3VHLFFBQVF5RixHQUN4Q0MsRUFBYzVGLEdERkEsaUJBRE9zRCxFQ0lWaFEsSURIZ0J1USxNQUFNQyxRQUFRUixJQUFrQixPQUFUQSxHQ0kvQ2hLLEVBQWNTLFNBQVNpRyxTQUNEOUYsSUFBdkIwTCxFQUFjNUYsUUFFQTlGLElBQVY1RyxFQUNFQSxFQUNBc1MsRUFBYzVGLEdBSGhCMEYsRUFBbUJFLEVBQWM1RixHQUFNMU0sRUFBT2dHLEdEUGhDLElBQUNnSyxFQ2F2QixPQUFPc0MsQ0FBYSxFQXFGdEIsU0FBU0MsR0FBb0JDLEVBQVdDLEVBQVksQ0FBQSxFQUFJck0sRUFBWSxJQUNsRUMsT0FBT0MsS0FBS2tNLEdBQVdqTSxTQUFTbUcsSUFDOUIsTUFBTWhHLEVBQVE4TCxFQUFVOUYsR0FDbEJnRyxFQUFjRCxHQUFhQSxFQUFVL0YsUUFFaEIsSUFBaEJoRyxFQUFNMUcsTUFDZnVTLEdBQW9CN0wsRUFBT2dNLEVBQWEsR0FBR3RNLEtBQWFzRyxXQUdwQzlGLElBQWhCOEwsSUFDRmhNLEVBQU0xRyxNQUFRMFMsR0FJWmhNLEVBQU1yRyxXQUFXeUgsUUFBZ0NsQixJQUF4QmtCLEVBQUtwQixFQUFNckcsV0FDdENxRyxFQUFNMUcsTUFBUThILEVBQUtwQixFQUFNckcsVUFFNUIsR0FFTCxDQVdBLFNBQVNzUyxHQUFZQyxHQUNuQixJQUFJNVIsRUFBVSxDQUFBLEVBQ2QsSUFBSyxNQUFPcUUsRUFBTTJLLEtBQVMzSixPQUFPdUcsUUFBUWdHLEdBQ3hDNVIsRUFBUXFFLEdBQVFnQixPQUFPb0ssVUFBVUMsZUFBZUMsS0FBS1gsRUFBTSxTQUN2REEsRUFBS2hRLE1BQ0wyUyxHQUFZM0MsR0FFbEIsT0FBT2hQLENBQ1QsQ0E2RUEsU0FBUzZSLEdBQWVDLEVBQWdCQyxFQUFhL1MsR0FDbkQsS0FBTytTLEVBQVl2TCxPQUFTLEdBQUcsQ0FDN0IsTUFBTXVJLEVBQVdnRCxFQUFZQyxRQWM3QixPQVhLM00sT0FBT29LLFVBQVVDLGVBQWVDLEtBQUttQyxFQUFnQi9DLEtBQ3hEK0MsRUFBZS9DLEdBQVksSUFJN0IrQyxFQUFlL0MsR0FBWThDLEdBQ3pCeE0sT0FBTzRNLE9BQU8sQ0FBQSxFQUFJSCxFQUFlL0MsSUFDakNnRCxFQUNBL1MsR0FHSzhTLENBQ1IsQ0FJRCxPQURBQSxFQUFlQyxFQUFZLElBQU0vUyxFQUMxQjhTLENBQ1QsQ0N0YUFJLGVBQWVDLEdBQU1DLEVBQUtDLEVBQWlCLElBQ3pDLE9BQU8sSUFBSUMsU0FBUSxDQUFDQyxFQUFTQyxLQUMzQixNQUFNQyxFQWJVLENBQUNMLEdBQVNBLEVBQUlqTCxXQUFXLFNBQVd1TCxFQUFRQyxFQWEzQ0MsQ0FBWVIsR0FFN0JLLEVBQ0dJLElBQUlULEVBQUtDLEdBQWlCUyxJQUN6QixJQUFJN0QsRUFBTyxHQUdYNkQsRUFBSUMsR0FBRyxRQUFTQyxJQUNkL0QsR0FBUStELENBQUssSUFJZkYsRUFBSUMsR0FBRyxPQUFPLEtBQ1A5RCxHQUNIdUQsRUFBTyxxQ0FHVE0sRUFBSUcsS0FBT2hFLEVBQ1hzRCxFQUFRTyxFQUFJLEdBQ1osSUFFSEMsR0FBRyxTQUFVM0csSUFDWm9HLEVBQU9wRyxFQUFNLEdBQ2IsR0FFUixDQ3BEQSxNQUFNOEcsV0FBb0JDLE1BQ3hCLFdBQUFDLENBQVk5TyxHQUNWK08sUUFDQUMsS0FBS2hQLFFBQVVBLEVBQ2ZnUCxLQUFLdkcsYUFBZXpJLENBQ3JCLENBRUQsUUFBQWlQLENBQVNuSCxHQVlQLE9BWEFrSCxLQUFLbEgsTUFBUUEsRUFDVEEsRUFBTS9ILE9BQ1JpUCxLQUFLalAsS0FBTytILEVBQU0vSCxNQUVoQitILEVBQU1vSCxhQUNSRixLQUFLRSxXQUFhcEgsRUFBTW9ILFlBRXRCcEgsRUFBTVksUUFDUnNHLEtBQUt2RyxhQUFlWCxFQUFNOUgsUUFDMUJnUCxLQUFLdEcsTUFBUVosRUFBTVksT0FFZHNHLElBQ1IsRUNXSCxNQUFNRyxHQUFRLENBQ1puVSxPQUFRLCtCQUNSb1UsZUFBZ0IsQ0FBRSxFQUNsQkMsUUFBUyxHQUNUQyxVQUFXLElBUUFDLEdBQWtCSixHQUN0QkEsRUFBTUUsUUFDVmhPLFVBQVUsRUFBRzhOLEVBQU1FLFFBQVFHLFFBQVEsT0FDbkNsRCxRQUFRLEtBQU0sSUFDZEEsUUFBUSxLQUFNLElBQ2RBLFFBQVEsTUFBTyxJQUNmdEssT0FnRVF5TixHQUF3QjdCLE1BQ25DOEIsRUFDQTNCLEVBQ0E0QixFQUNBQyxHQUFtQixLQUdmRixFQUFPMUcsU0FBUyxTQUNsQjBHLEVBQVNBLEVBQU9yTyxVQUFVLEVBQUdxTyxFQUFPeE4sT0FBUyxJQUcvQzhGLEVBQUksRUFBRyw2QkFBNkIwSCxRQUdwQyxNQUFNRyxRQUFpQmhDLEdBQU0sR0FBRzZCLE9BQWEzQixHQUc3QyxHQUE0QixNQUF4QjhCLEVBQVNYLFlBQThDLGlCQUFqQlcsRUFBU2xCLEtBQWtCLENBQ25FLEdBQUlnQixFQUFnQixDQUVsQkEsRUFEcUNELEVBNUV2QnBELFFBQ2hCLHFFQUNBLEtBMkUrQixDQUM5QixDQUVELE9BQU91RCxFQUFTbEIsSUFDakIsQ0FFRCxHQUFJaUIsRUFDRixNQUFNLElBQUloQixHQUNSLHVCQUF1QmMsMkVBQWdGRyxFQUFTWCxnQkFDaEhELFNBQVNZLEdBUWIsT0FORTdILEVBQ0UsRUFDQSwrQkFBK0IwSCw4REFJNUIsRUFBRSxFQStFRUksR0FBY2xDLE1BQ3pCbUMsRUFDQUMsRUFDQUMsS0FFQSxNQUFNblYsRUFBVWlWLEVBQWtCalYsUUFDNUJ3VSxFQUF3QixXQUFaeFUsR0FBeUJBLEVBQWUsR0FBR0EsS0FBUixHQUMvQ0UsRUFBUytVLEVBQWtCL1UsUUFBVW1VLEdBQU1uVSxPQUVqRGdOLEVBQ0UsRUFDQSxpREFBaURzSCxHQUFhLGFBR2hFLE1BQU1LLEVBQWlCLENBQUEsRUFDdkIsSUF3QkUsT0F2QkFSLEdBQU1FLGFBOUVrQnpCLE9BQzFCM1MsRUFDQUMsRUFDQUUsRUFDQTRVLEVBQ0FMLEtBR0EsSUFBSU8sRUFDSixNQUFNQyxFQUFZSCxFQUFhN1MsS0FDekJpVCxFQUFZSixFQUFhNVMsS0FHL0IsR0FBSStTLEdBQWFDLEVBQ2YsSUFDRUYsRUFBYSxJQUFJRyxFQUFBQSxnQkFBZ0IsQ0FDL0JsVCxLQUFNZ1QsRUFDTi9TLEtBQU1nVCxHQUVULENBQUMsTUFBT3RJLEdBQ1AsTUFBTSxJQUFJOEcsR0FBWSwyQ0FBMkNLLFNBQy9EbkgsRUFFSCxDQUlILE1BQU1pRyxFQUFpQm1DLEVBQ25CLENBQ0VJLE1BQU9KLEVBQ1AzUyxRQUFTaUYsRUFBSzBCLHNCQUVoQixHQUVFcU0sRUFBbUIsSUFDcEJ0VixFQUFZOEcsS0FBSzJOLEdBQ2xCRCxHQUFzQixHQUFHQyxJQUFVM0IsRUFBZ0I0QixHQUFnQixRQUVsRXpVLEVBQWM2RyxLQUFLMk4sR0FDcEJELEdBQXNCLEdBQUdDLElBQVUzQixFQUFnQjRCLFFBRWxEdlUsRUFBYzJHLEtBQUsyTixHQUNwQkQsR0FBc0IsR0FBR0MsSUFBVTNCLE1BS3ZDLGFBRDZCQyxRQUFRd0MsSUFBSUQsSUFDbkJyUSxLQUFLLE1BQU0sRUErQlR1USxDQUNwQixJQUNLVixFQUFrQjlVLFlBQVk4RyxLQUFLMk8sR0FBTSxHQUFHMVYsSUFBU3NVLElBQVlvQixPQUV0RSxJQUNLWCxFQUFrQjdVLGNBQWM2RyxLQUFLNE8sR0FDaEMsUUFBTkEsRUFDSSxHQUFHM1YsU0FBY3NVLFlBQW9CcUIsSUFDckMsR0FBRzNWLElBQVNzVSxZQUFvQnFCLFNBRW5DWixFQUFrQjVVLGlCQUFpQjRHLEtBQ25DZ0ssR0FBTSxHQUFHL1EsVUFBZXNVLGVBQXVCdkQsT0FHcERnRSxFQUFrQjNVLGNBQ2xCNFUsRUFDQUwsR0FHRlIsR0FBTUcsVUFBWUMsR0FBZUosSUFHakN5QixFQUFBQSxjQUFjWCxFQUFZZCxHQUFNRSxTQUN6Qk0sQ0FDUixDQUFDLE1BQU83SCxHQUNQLE1BQU0sSUFBSThHLEdBQ1Isd0RBQ0FLLFNBQVNuSCxFQUNaLEdBaUNVK0ksR0FBc0JqRCxNQUFPbFMsSUFDeEMsTUFBTWIsV0FBRUEsRUFBVW1DLE9BQUVBLEdBQVd0QixFQUN6QkosRUFBWTRFLEVBQUlBLEtBQUMrSSxFQUFXcE8sRUFBV1MsV0FFN0MsSUFBSXFVLEVBRUosTUFBTW1CLEVBQWU1USxFQUFBQSxLQUFLNUUsRUFBVyxpQkFDL0IyVSxFQUFhL1AsRUFBQUEsS0FBSzVFLEVBQVcsY0FPbkMsSUFKQ29NLEVBQVVBLFdBQUNwTSxJQUFjcU0sRUFBU0EsVUFBQ3JNLElBSS9Cb00sRUFBQUEsV0FBV29KLElBQWlCalcsRUFBV1EsV0FDMUMyTSxFQUFJLEVBQUcseURBQ1AySCxRQUF1QkcsR0FBWWpWLEVBQVltQyxFQUFPTSxNQUFPMlMsT0FDeEQsQ0FDTCxJQUFJYyxHQUFnQixFQUdwQixNQUFNQyxFQUFXbkcsS0FBS3BFLE1BQU04RCxFQUFBQSxhQUFhdUcsSUFJekMsR0FBSUUsRUFBUzNXLFNBQVc0USxNQUFNQyxRQUFROEYsRUFBUzNXLFNBQVUsQ0FDdkQsTUFBTTRXLEVBQVksQ0FBQSxFQUNsQkQsRUFBUzNXLFFBQVE0RyxTQUFTMFAsR0FBT00sRUFBVU4sR0FBSyxJQUNoREssRUFBUzNXLFFBQVU0VyxDQUNwQixDQUVELE1BQU1oVyxZQUFFQSxFQUFXQyxjQUFFQSxFQUFhQyxpQkFBRUEsR0FBcUJOLEVBQ25EcVcsRUFDSmpXLEVBQVlpSCxPQUFTaEgsRUFBY2dILE9BQVMvRyxFQUFpQitHLE9BSzNEOE8sRUFBU2xXLFVBQVlELEVBQVdDLFNBQ2xDa04sRUFDRSxFQUNBLHlFQUVGK0ksR0FBZ0IsR0FDUGhRLE9BQU9DLEtBQUtnUSxFQUFTM1csU0FBVyxJQUFJNkgsU0FBV2dQLEdBQ3hEbEosRUFDRSxFQUNBLCtFQUVGK0ksR0FBZ0IsR0FHaEJBLEdBQWlCN1YsR0FBaUIsSUFBSWlXLE1BQU1DLElBQzFDLElBQUtKLEVBQVMzVyxRQUFRK1csR0FLcEIsT0FKQXBKLEVBQ0UsRUFDQSxlQUFlb0osaURBRVYsQ0FDUixJQUlETCxFQUNGcEIsUUFBdUJHLEdBQVlqVixFQUFZbUMsRUFBT00sTUFBTzJTLElBRTdEakksRUFBSSxFQUFHLHVEQUdQbUgsR0FBTUUsUUFBVTlFLEVBQUFBLGFBQWEwRixFQUFZLFFBR3pDTixFQUFpQnFCLEVBQVMzVyxRQUUxQjhVLEdBQU1HLFVBQVlDLEdBQWVKLElBRXBDLE1BclRpQ3ZCLE9BQU9wTSxFQUFRbU8sS0FDakQsTUFBTTBCLEVBQWMsQ0FDbEJ2VyxRQUFTMEcsRUFBTzFHLFFBQ2hCVCxRQUFTc1YsR0FBa0IsQ0FBRSxHQUkvQlIsR0FBTUMsZUFBaUJpQyxFQUV2QnJKLEVBQUksRUFBRyxtQ0FDUCxJQUNFNEksRUFBYUEsY0FDWDFRLEVBQUFBLEtBQUsrSSxFQUFXekgsRUFBT2xHLFVBQVcsaUJBQ2xDdVAsS0FBS0MsVUFBVXVHLEdBQ2YsT0FFSCxDQUFDLE1BQU92SixHQUNQLE1BQU0sSUFBSThHLEdBQVksNkNBQTZDSyxTQUNqRW5ILEVBRUgsR0FxU0t3SixDQUFxQnpXLEVBQVk4VSxFQUFlLEVBRzNDNEIsR0FBZSxJQUMxQnJSLEVBQUFBLEtBQUsrSSxFQUFXNEQsSUFBYWhTLFdBQVdTLFdBRTFDLElBQWVrVyxHQTFHYzVELE1BQU82RCxJQUNsQyxNQUFNL1YsRUFBVW1SLElBQ1puUixHQUFTYixhQUNYYSxFQUFRYixXQUFXQyxRQUFVMlcsU0FFekJaLEdBQW9CblYsRUFBUSxFQXFHckI4VixHQUlILElBQU1yQyxHQUpIcUMsR0FNSixJQUFNckMsR0FBTUcsVUMzWGhCLFNBQVNvQyxLQUNkQyxXQUFXQyxXQUFhLFdBQ3RCLE1BQU8sQ0FBRUMsU0FBVSxFQUN2QixDQUNBLENBU08sU0FBU0MsR0FBY0MsRUFBY3JXLEVBQVNzVyxHQUVuRHRVLE9BQU91VSxlQUFpQkQsRUFHeEIsTUFBTW5GLFdBQUVBLEVBQVVxRixNQUFFQSxFQUFLQyxXQUFFQSxFQUFVQyxLQUFFQSxHQUFTVCxXQUloREEsV0FBV1UsY0FBZ0JILEdBQU0sRUFBTyxDQUFFLEVBQUVyRixLQUd4Q25SLEVBQVFhLFlBQVlHLFlBQ3RCLElBQUk0VixTQUFTNVcsRUFBUWEsWUFBWUcsV0FBakMsR0FJRixNQUFNNlYsRUFBUSxDQUNaQyxXQUFXLEdBSVQ5VyxFQUFRSCxPQUFPa1gsU0FDakJGLEVBQU12VyxPQUFTK1YsRUFBYVEsTUFBTXZXLE9BQ2xDdVcsRUFBTXRXLE1BQVE4VixFQUFhUSxNQUFNdFcsT0FJbkN5QixPQUFPZ1Ysa0JBQW1CLEVBQzFCTixFQUFLVCxXQUFXZ0IsTUFBTXhILFVBQVcsUUFBUSxTQUFVeUgsRUFBU0MsRUFBYUMsS0FFdkVELEVBQWNYLEVBQU1XLEVBQWEsQ0FDL0JFLFVBQVcsQ0FDVEMsU0FBUyxHQUVYQyxZQUFhLENBQ1hDLE9BQVEsQ0FDTkMsTUFBTyxDQUNMSCxTQUFTLEtBT2ZJLFFBQVMsQ0FBRSxLQUdBRixRQUFVLElBQUlqUyxTQUFRLFNBQVVpUyxHQUMzQ0EsRUFBT1YsV0FBWSxDQUN6QixJQUdTOVUsT0FBTzJWLHFCQUNWM1YsT0FBTzJWLG1CQUFxQjFCLFdBQVcyQixTQUFTdEUsS0FBTSxVQUFVLEtBQzlEdFIsT0FBT2dWLGtCQUFtQixDQUFJLEtBSWxDRSxFQUFRdkssTUFBTTJHLEtBQU0sQ0FBQzZELEVBQWFDLEdBQ3RDLElBRUVWLEVBQUtULFdBQVc0QixPQUFPcEksVUFBVyxRQUFRLFNBQVV5SCxFQUFTTCxFQUFPN1csR0FDbEVrWCxFQUFRdkssTUFBTTJHLEtBQU0sQ0FBQ3VELEVBQU83VyxHQUNoQyxJQUdFLE1BQU1tWCxFQUFjblgsRUFBUUgsT0FBT2tYLE9BQy9CLElBQUlILFNBQVMsVUFBVTVXLEVBQVFILE9BQU9rWCxTQUF0QyxHQUNBVixFQUlFeUIsRUFBZXRCLEdBQ25CLEVBQ0FySCxLQUFLcEUsTUFBTS9LLEVBQVFILE9BQU9hLGNBQzFCeVcsRUFFQSxDQUFFTixVQUdFa0IsRUFBZ0IvWCxFQUFRYSxZQUFZSSxTQUN0QyxJQUFJMlYsU0FBUyxVQUFVNVcsRUFBUWEsWUFBWUksV0FBM0MsUUFDQTJFLEVBR0VuRixFQUFnQjBPLEtBQUtwRSxNQUFNL0ssRUFBUUgsT0FBT1ksZUFDNUNBLEdBQ0ZnVyxFQUFXaFcsR0FHYndWLFdBQVdqVyxFQUFRSCxPQUFPSyxRQUFVLFNBQ2xDLFlBQ0E0WCxFQUNBQyxHQUlGLE1BQU1DLEVBQWlCN0csSUFHdkIsSUFBSyxNQUFNOEcsS0FBUUQsRUFDbUIsbUJBQXpCQSxFQUFlQyxXQUNqQkQsRUFBZUMsR0FLMUJ4QixFQUFXUixXQUFXVSxlQUd0QlYsV0FBV1UsY0FBZ0IsRUFDN0IsQ0NySEEsTUFBTXBKLEdBQVk2RSxFQUFJNUUsY0FBYyxJQUFJQyxJQUFJLElBQW9CLG9CQUFBQyxTQUFBQyxRQUFBLE9BQUFDLGNBQUFDLFlBQUFDLEtBQUFDLEdBQUFBLEVBQUFDLEtBQUEsSUFBQVAsSUFBQSxZQUFBQyxTQUFBTyxTQUFBSCxPQUMxRG9LLEdBQVdDLEVBQUd0SixhQUNsQnRCLEdBQVksOEJBQ1osUUFHRixJQUFJNkssR0F1SEdsRyxlQUFlbUcsS0FDcEIsSUFBS0QsR0FDSCxPQUFPLEVBSVQsTUFBTUUsUUFBYUYsR0FBUUMsVUFRM0IsYUFMTUMsRUFBS0MsaUJBQWdCLFNBR3JCQyxHQUFlRixHQUVkQSxDQUNULENBK0NBcEcsZUFBZXNHLEdBQWVGLFNBQ3RCQSxFQUFLRyxXQUFXUCxHQUFVLENBQUVRLFVBQVcsMkJBR3ZDSixFQUFLSyxhQUFhLENBQUVDLEtBQU0sR0FBRy9DLDBCQUc3QnlDLEVBQUtPLFNBQVM3QyxHQUN0QixDQ3JNQSxNQUFNOEMsR0FBWTFHLEVBQUk1RSxjQUFjLElBQUlDLElBQUksSUFBb0Isb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsR0FBQUEsRUFBQUMsS0FBQSxJQUFBUCxJQUFBLFlBQUFDLFNBQUFPLFNBQUFILE9BbUgxRGlMLEdBQWMsQ0FBQ1QsRUFBTXpCLEVBQU83VyxFQUFTc1csSUFDekNnQyxFQUFLTyxTQUFTekMsR0FBZVMsRUFBTzdXLEVBQVNzVyxHQVkvQyxJQUFBMEMsR0FBZTlHLE1BQU9vRyxFQUFNekIsRUFBTzdXLEtBTWpDLE1BQU1pWixFQUFvQixHQUdwQkMsRUFBZ0JoSCxNQUFPb0csSUFDM0IsSUFBSyxNQUFNYSxLQUFZRixRQUNmRSxFQUFTQyxnQkFJWGQsRUFBS08sVUFBUyxLQUdsQixHQUEwQixvQkFBZjVDLFdBQTRCLENBRXJDLE1BQU1vRCxFQUFZcEQsV0FBV3FELE9BRzdCLEdBQUkvSixNQUFNQyxRQUFRNkosSUFBY0EsRUFBVTdTLE9BRXhDLElBQUssTUFBTStTLEtBQVlGLEVBQ3JCRSxHQUFZQSxFQUFTQyxVQUVyQnZELFdBQVdxRCxPQUFPdEgsT0FHdkIsQ0FHRCxTQUFVeUgsR0FBbUIvTCxTQUFTZ00scUJBQXFCLFdBRXJELElBQU1DLEdBQWtCak0sU0FBU2dNLHFCQUFxQixhQUVsREUsR0FBaUJsTSxTQUFTZ00scUJBQXFCLFFBR3pELElBQUssTUFBTUcsSUFBVyxJQUNqQkosS0FDQUUsS0FDQUMsR0FFSEMsRUFBUUMsUUFDVCxHQUNELEVBR0osSUFDRXhOLEVBQUksRUFBRyxxQ0FFUCxNQUFNeU4sRUFBZ0IvWixFQUFRSCxPQUd4QnlXLEVBQ0p5RCxHQUFlL1osU0FBUzZXLE9BQU9QLGVBQy9CN0MsS0FBaUJDLGVBQWUvVSxRQUFRcWIsU0FFMUMsSUFBSUMsRUFDSixHQUNFcEQsRUFBTS9DLFVBQ0wrQyxFQUFNL0MsUUFBUSxTQUFXLEdBQUsrQyxFQUFNL0MsUUFBUSxVQUFZLEdBQ3pELENBS0EsR0FIQXhILEVBQUksRUFBRyw2QkFHb0IsUUFBdkJ5TixFQUFjOWEsS0FDaEIsT0FBTzRYLEVBR1RvRCxHQUFRLFFBQ0YzQixFQUFLRyxXQ3BORixDQUFDNUIsR0FBVSxrbkJBWWxCQSx3Q0R3TW9CcUQsQ0FBWXJELEdBQVEsQ0FDeEM2QixVQUFXLG9CQUVuQixNQUVNcE0sRUFBSSxFQUFHLGdDQUdIeU4sRUFBY2hELGFBRVZnQyxHQUNKVCxFQUNBLENBQ0V6QixNQUFPLENBQ0x2VyxPQUFReVosRUFBY3paLE9BQ3RCQyxNQUFPd1osRUFBY3haLFFBR3pCUCxFQUNBc1csSUFJRk8sRUFBTUEsTUFBTXZXLE9BQVN5WixFQUFjelosT0FDbkN1VyxFQUFNQSxNQUFNdFcsTUFBUXdaLEVBQWN4WixZQUU1QndZLEdBQVlULEVBQU16QixFQUFPN1csRUFBU3NXLElBSzVDLE1BQU1wVixFQUFZbEIsRUFBUWEsWUFBWUssVUFDdEMsR0FBSUEsRUFBVyxDQUNiLE1BQU1pWixFQUFhLEdBVW5CLEdBUElqWixFQUFVa1osSUFDWkQsRUFBV0UsS0FBSyxDQUNkQyxRQUFTcFosRUFBVWtaLEtBS25CbFosRUFBVTROLE1BQ1osSUFBSyxNQUFNMUwsS0FBUWxDLEVBQVU0TixNQUFPLENBQ2xDLE1BQU15TCxHQUFXblgsRUFBSytELFdBQVcsUUFHakNnVCxFQUFXRSxLQUNURSxFQUNJLENBQ0VELFFBQVN6TCxFQUFBQSxhQUFhekwsRUFBTSxTQUU5QixDQUNFZ1AsSUFBS2hQLEdBR2QsQ0FHSCxJQUFLLE1BQU1vWCxLQUFjTCxFQUN2QixJQUNFbEIsRUFBa0JvQixXQUFXL0IsRUFBS0ssYUFBYTZCLEdBQ2hELENBQUMsTUFBT3BPLEdBQ1BRLEVBQWEsRUFBR1IsRUFBTyw2Q0FDeEIsQ0FFSCtOLEVBQVczVCxPQUFTLEVBR3BCLE1BQU1pVSxFQUFjLEdBQ3BCLEdBQUl2WixFQUFVd1osSUFBSyxDQUNqQixJQUFJQyxFQUFhelosRUFBVXdaLElBQUlFLE1BQU0sdUJBQ3JDLEdBQUlELEVBRUYsSUFBSyxJQUFJRSxLQUFpQkYsRUFDcEJFLElBQ0ZBLEVBQWdCQSxFQUNiakssUUFBUSxPQUFRLElBQ2hCQSxRQUFRLFVBQVcsSUFDbkJBLFFBQVEsS0FBTSxJQUNkQSxRQUFRLEtBQU0sSUFDZEEsUUFBUSxJQUFLLElBQ2JBLFFBQVEsTUFBTyxJQUNmdEssT0FHQ3VVLEVBQWMxVCxXQUFXLFFBQzNCc1QsRUFBWUosS0FBSyxDQUNmakksSUFBS3lJLElBRUU3YSxFQUFRYSxZQUFZRSxvQkFDN0IwWixFQUFZSixLQUFLLENBQ2Z6QixLQUFNQSxFQUFLcFUsS0FBS3NVLEdBQVcrQixNQVFyQ0osRUFBWUosS0FBSyxDQUNmQyxRQUFTcFosRUFBVXdaLElBQUk5SixRQUFRLHNCQUF1QixLQUFPLE1BRy9ELElBQUssTUFBTWtLLEtBQWVMLEVBQ3hCLElBQ0V4QixFQUFrQm9CLFdBQVcvQixFQUFLeUMsWUFBWUQsR0FDL0MsQ0FBQyxNQUFPMU8sR0FDUFEsRUFDRSxFQUNBUixFQUNBLDhDQUVILENBRUhxTyxFQUFZalUsT0FBUyxDQUN0QixDQUNGLENBR0QsTUFBTXdVLEVBQU9mLFFBQ0gzQixFQUFLTyxVQUFVclksSUFDbkIsTUFBTXlhLEVBQWF2TixTQUFTd04sY0FDMUIsc0NBSUlDLEVBQWNGLEVBQVczYSxPQUFPOGEsUUFBUXBjLE1BQVF3QixFQUNoRDZhLEVBQWFKLEVBQVcxYSxNQUFNNmEsUUFBUXBjLE1BQVF3QixFQVdwRCxPQU5Ba04sU0FBUzROLEtBQUtDLE1BQU1DLEtBQU9oYixFQUkzQmtOLFNBQVM0TixLQUFLQyxNQUFNRSxPQUFTLE1BRXRCLENBQ0xOLGNBQ0FFLGFBQ0QsR0FDQXhVLFdBQVdrVCxFQUFjdlosY0FDdEI4WCxFQUFLTyxVQUFTLEtBRWxCLE1BQU1zQyxZQUFFQSxFQUFXRSxXQUFFQSxHQUFlclosT0FBT2lVLFdBQVdxRCxPQUFPLEdBTzdELE9BRkE1TCxTQUFTNE4sS0FBS0MsTUFBTUMsS0FBTyxFQUVwQixDQUNMTCxjQUNBRSxhQUNELElBSURLLEVBQWlCQyxLQUFLQyxLQUFLWixFQUFLRyxhQUFlcEIsRUFBY3paLFFBQzdEdWIsRUFBZ0JGLEtBQUtDLEtBQUtaLEVBQUtLLFlBQWN0QixFQUFjeFosUUFHM0R1YixFQUFFQSxFQUFDQyxFQUFFQSxRQXJXTyxDQUFDekQsR0FDckJBLEVBQUswRCxNQUFNLG9CQUFxQm5DLElBQzlCLE1BQU1pQyxFQUFFQSxFQUFDQyxFQUFFQSxFQUFDeGIsTUFBRUEsRUFBS0QsT0FBRUEsR0FBV3VaLEVBQVFvQyx3QkFDeEMsTUFBTyxDQUNMSCxJQUNBQyxJQUNBeGIsUUFDQUQsT0FBUXFiLEtBQUtPLE1BQU01YixFQUFTLEVBQUlBLEVBQVMsS0FDMUMsSUE2VnNCNmIsQ0FBYzdELEdBU3JDLElBQUlySixFQUVKLFNBUk1xSixFQUFLOEQsWUFBWSxDQUNyQjliLE9BQVFvYixFQUNSbmIsTUFBT3NiLEVBQ1BRLGtCQUFtQnBDLEVBQVEsRUFBSXBULFdBQVdrVCxFQUFjdlosU0FLL0IsUUFBdkJ1WixFQUFjOWEsS0FFaEJnUSxPQXZSWSxDQUFDcUosR0FDakJBLEVBQUswRCxNQUFNLGdDQUFpQ25DLEdBQVlBLEVBQVF5QyxZQXNSL0NDLENBQVVqRSxRQUNsQixHQUFJLENBQUMsTUFBTyxRQUFRN1MsU0FBU3NVLEVBQWM5YSxNQUVoRGdRLE9BNVZjLEVBQUNxSixFQUFNclosRUFBTXVkLEVBQVVDLEVBQU03YixJQUMvQzBSLFFBQVFvSyxLQUFLLENBQ1hwRSxFQUFLcUUsV0FBVyxDQUNkMWQsT0FDQXVkLFdBQ0FDLE9BQ0FHLHVCQUF1QixFQUN2QkMsVUFBVSxFQUNWQyxrQkFBa0IsS0FDTCxRQUFUN2QsRUFBaUIsQ0FBRThkLFFBQVMsSUFBTyxDQUFFLEVBSXpDQyxlQUF3QixPQUFSL2QsSUFFbEIsSUFBSXFULFNBQVEsQ0FBQzJLLEVBQVV6SyxJQUNyQjBLLFlBQ0UsSUFBTTFLLEVBQU8sSUFBSVUsR0FBWSwyQkFDN0J0UyxHQUF3QixVQTBVYnVjLENBQ1g3RSxFQUNBeUIsRUFBYzlhLEtBQ2QsU0FDQSxDQUNFc0IsTUFBT3NiLEVBQ1B2YixPQUFRb2IsRUFDUkksSUFDQUMsS0FFRmhDLEVBQWNuWiwwQkFFWCxJQUEyQixRQUF2Qm1aLEVBQWM5YSxLQVV2QixNQUFNLElBQUlpVSxHQUNSLHNDQUFzQzZHLEVBQWM5YSxTQVR0RGdRLE9BeFVZaUQsT0FDaEJvRyxFQUNBaFksRUFDQUMsRUFDQWljLEVBQ0E1YixXQUVNMFgsRUFBSzhFLGlCQUFpQixVQUNyQjlLLFFBQVFvSyxLQUFLLENBQ2xCcEUsRUFBSytFLElBQUksQ0FFUC9jLE9BQVFBLEVBQVMsRUFDakJDLFFBQ0FpYyxhQUVGLElBQUlsSyxTQUFRLENBQUMySyxFQUFVekssSUFDckIwSyxZQUNFLElBQU0xSyxFQUFPLElBQUlVLEdBQVksMkJBQzdCdFMsR0FBd0IsV0FzVGIwYyxDQUNYaEYsRUFDQW9ELEVBQ0FHLEVBQ0EsU0FDQTlCLEVBQWNuWixxQkFNakIsQ0FHRCxhQURNc1ksRUFBY1osR0FDYnJKLENBQ1IsQ0FBQyxNQUFPN0MsR0FFUCxhQURNOE0sRUFBY1osR0FDYmxNLENBQ1IsR0UxWkgsSUFBSTVKLElBQU8sRUFHSixNQUFNK2EsR0FBUSxDQUNuQkMsaUJBQWtCLEVBQ2xCQyxlQUFnQixFQUNoQkMsc0JBQXVCLEVBQ3ZCQyxVQUFXLEVBQ1hDLGVBQWdCLEVBQ2hCQyxhQUFjLEdBR2hCLElBQUlDLEdBQWEsQ0FBQSxFQUVqQixNQUFNQyxHQUFVLENBVWRDLE9BQVE5TCxVQUNOLElBQUlvRyxHQUFPLEVBRVgsTUFBTTJGLEVBQUtDLEVBQUFBLEtBQ0xDLEdBQVksSUFBSTNSLE1BQU80UixVQUU3QixJQUdFLEdBRkE5RixRQUFhK0YsTUFFUi9GLEdBQVFBLEVBQUtnRyxXQUNoQixNQUFNLElBQUlwTCxHQUFZLGtDQUd4QjVHLEVBQ0UsRUFDQSx3Q0FBd0MyUixhQUN0QyxJQUFJelIsTUFBTzRSLFVBQVlELFFBRzVCLENBQUMsTUFBTy9SLEdBQ1AsTUFBTSxJQUFJOEcsR0FDUiwrQ0FDQUssU0FBU25ILEVBQ1osQ0FFRCxNQUFNdkksTUFBRUEsR0FBVXNOLElBd0JsQixPQXRCSXROLEVBQU10QyxRQUFVc0MsRUFBTUcsaUJBQ3hCc1UsRUFBS3ZGLEdBQUcsV0FBWXpPLElBQ2xCK0gsUUFBUUMsSUFBSSxXQUFXaEksRUFBUTJPLFNBQVMsSUFLNUNxRixFQUFLdkYsR0FBRyxhQUFhYixNQUFPOUYsVUFHcEJrTSxFQUFLMEQsTUFDVCxjQUNBLENBQUNuQyxFQUFTMEUsS0FFSnZjLE9BQU91VSxpQkFDVHNELEVBQVEyRSxVQUFZRCxFQUNyQixHQUVILG9DQUFvQ25TLEVBQU1LLGFBQzNDLElBR0ksQ0FDTHdSLEtBQ0EzRixPQUVBbUcsVUFBVzlDLEtBQUs1VyxNQUFNNFcsS0FBSytDLFVBQVlaLEdBQVduYixVQUFZLElBQy9ELEVBYUhnYyxTQUFVek0sTUFBTzBNLEtBRWJkLEdBQVduYixhQUNUaWMsRUFBYUgsVUFBWVgsR0FBV25iLGFBRXRDMkosRUFDRSxFQUNBLGtFQUFrRXdSLEdBQVduYixnQkFFeEUsR0FXWDZXLFFBQVN0SCxNQUFPME0sSUFDZHRTLEVBQUksRUFBRyxnQ0FBZ0NzUyxFQUFhWCxPQUVoRFcsRUFBYXRHLFlBRVRzRyxFQUFhdEcsS0FBS3VHLE9BQ3pCLEdBV1FDLEdBQVc1TSxNQUFPcE0sSUFZN0IsR0FWQWdZLEdBQWFoWSxHQUFVQSxFQUFPdEQsS0FBTyxJQUFLc0QsRUFBT3RELE1BQVMsU0huR3JEMFAsZUFBc0I2TSxHQUUzQixNQUFReGQsT0FBUXlkLEtBQWlCbmIsR0FBVXNOLElBQWF0TixNQUNsRG9iLEVBQWdCLENBQ3BCbmIsU0FBVSxRQUNWb2IsWUFBYSxTQUNibmdCLEtBQU1nZ0IsRUFDTkksY0FBYyxFQUNkQyxlQUFlLEVBQ2ZDLGNBQWMsRUFDZEMsb0JBQW9CLEVBQ3BCQyxnQkFBaUIsUUFDYlAsR0FBZ0JuYixHQUl0QixJQUFLdVUsR0FBUyxDQUNaLElBQUlvSCxFQUFXLEVBRWYsTUFBTUMsRUFBT3ZOLFVBQ1gsSUFDRTVGLEVBQ0UsRUFDQSx5REFBeURrVCxPQUUzRHBILFNBQWdCdFosRUFBVTRnQixPQUFPVCxFQUNsQyxDQUFDLE1BQU83UyxHQVFQLEdBUEFRLEVBQ0UsRUFDQVIsRUFDQSxvREFJRW9ULEVBQVcsSUFLYixNQUFNcFQsRUFKTkUsRUFBSSxFQUFHLHNDQUFzQ2tULHVCQUN2QyxJQUFJbE4sU0FBUzZCLEdBQWErSSxXQUFXL0ksRUFBVSxhQUMvQ3NMLEdBSVQsR0FHSCxVQUNRQSxJQUVGVCxHQUNGMVMsRUFBSSxFQUFHLDRDQUVWLENBQUMsTUFBT0YsR0FDUCxNQUFNLElBQUk4RyxHQUNSLGlFQUNBSyxTQUFTbkgsRUFDWixDQUVELElBQUtnTSxHQUNILE1BQU0sSUFBSWxGLEdBQVksMkNBRXpCLENBR0QsT0FBT2tGLEVBQ1QsQ0d1Q1F1SCxDQUFjN1osRUFBT2laLGVBRTNCelMsRUFDRSxFQUNBLDhDQUE4Q3dSLEdBQVdyYixtQkFBbUJxYixHQUFXcGIsZUFHckZGLEdBQ0YsT0FBTzhKLEVBQ0wsRUFDQSx5RUFJQXNULFNBQVM5QixHQUFXcmIsWUFBY21kLFNBQVM5QixHQUFXcGIsY0FDeERvYixHQUFXcmIsV0FBYXFiLEdBQVdwYixZQUdyQyxJQUVFRixHQUFPLElBQUlxZCxFQUFBQSxLQUFLLElBRVg5QixHQUNIbFosSUFBSythLFNBQVM5QixHQUFXcmIsWUFDekJxQyxJQUFLOGEsU0FBUzlCLEdBQVdwYixZQUN6Qm9kLHFCQUFzQmhDLEdBQVdsYixlQUNqQ21kLG9CQUFxQmpDLEdBQVdqYixjQUNoQ21kLHFCQUFzQmxDLEdBQVdoYixlQUNqQ21kLGtCQUFtQm5DLEdBQVcvYSxZQUM5Qm1kLDBCQUEyQnBDLEdBQVc5YSxvQkFDdENtZCxtQkFBb0JyQyxHQUFXN2EsZUFDL0JtZCxzQkFBc0IsSUFJeEI1ZCxHQUFLdVEsR0FBRyxXQUFXYixNQUFPaUgsVUhuQnZCakgsZUFBeUJvRyxFQUFNK0gsR0FBWSxHQUNoRCxJQUNPL0gsRUFBS2dHLGFBQ0orQixTQUVJL0gsRUFBS2dJLEtBQUssY0FBZSxDQUFFNUgsVUFBVywyQkFHdENGLEdBQWVGLFVBR2ZBLEVBQUtPLFVBQVMsS0FDbEJuTCxTQUFTNE4sS0FBS2tELFVBQ1osNERBQTRELElBSXJFLENBQUMsTUFBT3BTLEdBQ1BRLEVBQ0UsRUFDQVIsRUFDQSxxREFFSCxDQUNILENHSFltVSxDQUFVcEgsRUFBU2IsTUFBTSxHQUMvQmhNLEVBQUksRUFBRyxxQ0FBcUM2TSxFQUFTOEUsTUFBTSxJQUc3RHpiLEdBQUt1USxHQUFHLGtCQUFrQixDQUFDeU4sRUFBU3JILEtBQ2xDN00sRUFBSSxFQUFHLHFDQUFxQzZNLEVBQVM4RSxNQUFNLElBRzdELE1BQU13QyxFQUFtQixHQUV6QixJQUFLLElBQUlwUSxFQUFJLEVBQUdBLEVBQUl5TixHQUFXcmIsV0FBWTROLElBQ3pDLElBQ0UsTUFBTThJLFFBQWlCM1csR0FBS2tlLFVBQVVDLFFBQ3RDRixFQUFpQnBHLEtBQUtsQixFQUN2QixDQUFDLE1BQU8vTSxHQUNQUSxFQUFhLEVBQUdSLEVBQU8sK0NBQ3hCLENBSUhxVSxFQUFpQmxiLFNBQVM0VCxJQUN4QjNXLEdBQUtvZSxRQUFRekgsRUFBUyxJQUd4QjdNLEVBQ0UsRUFDQSw0QkFBMkJtVSxFQUFpQmphLE9BQVMsU0FBU2lhLEVBQWlCamEsb0NBQXNDLEtBRXhILENBQUMsTUFBTzRGLEdBQ1AsTUFBTSxJQUFJOEcsR0FDUixnREFDQUssU0FBU25ILEVBQ1osR0FVSThGLGVBQWUyTyxLQUlwQixHQUhBdlUsRUFBSSxFQUFHLDZEQUdIOUosR0FBTSxDQUVSLElBQUssTUFBTXNlLEtBQVV0ZSxHQUFLdWUsS0FDeEJ2ZSxHQUFLb2UsUUFBUUUsRUFBTzNILFVBSWpCM1csR0FBS3dlLGtCQUNGeGUsR0FBS2dYLFVBQ1hsTixFQUFJLEVBQUcsOENBRVYsT0g3SEk0RixpQkFFRGtHLElBQVM2SSxpQkFDTDdJLEdBQVF5RyxRQUVoQnZTLEVBQUksRUFBRyxnQ0FDVCxDRzBIUTRVLEVBQ1IsQ0FlTyxNQUFNQyxHQUFXalAsTUFBTzJFLEVBQU83VyxLQUNwQyxJQUFJNGUsRUFFSixJQVFFLEdBUEF0UyxFQUFJLEVBQUcsZ0RBRUxpUixHQUFNRSxlQUNKSyxHQUFXbmMsY0FDYnlmLE1BR0c1ZSxHQUNILE1BQU0sSUFBSTBRLEdBQVksaURBSXhCLE1BQU1tTyxFQUFpQnhRLElBQ3ZCLElBQ0V2RSxFQUFJLEVBQUcscUNBQ1BzUyxRQUFxQnBjLEdBQUtrZSxVQUFVQyxRQUdoQzNnQixFQUFRc0IsT0FBT0ssY0FDakIySyxFQUNFLEVBQ0F0TSxFQUFRc2hCLFNBQVNDLFVBQ2IsK0JBQStCdmhCLEVBQVFzaEIsU0FBU0MsY0FDaEQsY0FDSiw2QkFBNkJGLFNBR2xDLENBQUMsTUFBT2pWLEdBQ1AsTUFBTSxJQUFJOEcsSUFDUGxULEVBQVFzaEIsU0FBU0MsVUFDZCx1QkFBdUJ2aEIsRUFBUXNoQixTQUFTQyxlQUN4QyxJQUNGLHdEQUF3REYsVUFDMUQ5TixTQUFTbkgsRUFDWixDQUdELEdBRkFFLEVBQUksRUFBRyxxQ0FFRnNTLEVBQWF0RyxLQUNoQixNQUFNLElBQUlwRixHQUNSLDZEQUtKLElBQUlzTyxHQUFZLElBQUloVixNQUFPNFIsVUFFM0I5UixFQUFJLEVBQUcsOENBQThDc1MsRUFBYVgsT0FHbEUsTUFBTXdELEVBQWdCNVEsSUFDaEI2USxRQUFlMUksR0FBZ0I0RixFQUFhdEcsS0FBTXpCLEVBQU83VyxHQUcvRCxHQUFJMGhCLGFBQWtCdk8sTUFPcEIsS0FMdUIsMEJBQW5CdU8sRUFBT3BkLFVBQ1RzYSxFQUFhdEcsS0FBS3VHLFFBQ2xCRCxFQUFhdEcsV0FBYStGLE1BR3RCLElBQUluTCxJQUNQbFQsRUFBUXNoQixTQUFTQyxVQUNkLHVCQUF1QnZoQixFQUFRc2hCLFNBQVNDLGVBQ3hDLElBQU0sb0NBQW9DRSxVQUM5Q2xPLFNBQVNtTyxHQUlUMWhCLEVBQVFzQixPQUFPSyxjQUNqQjJLLEVBQ0UsRUFDQXRNLEVBQVFzaEIsU0FBU0MsVUFDYiwrQkFBK0J2aEIsRUFBUXNoQixTQUFTQyxjQUNoRCxjQUNKLGlDQUFpQ0UsVUFLckNqZixHQUFLb2UsUUFBUWhDLEdBSWIsTUFDTStDLEdBRFUsSUFBSW5WLE1BQU80UixVQUNFb0QsRUFPN0IsT0FOQWpFLEdBQU1JLFdBQWFnRSxFQUNuQnBFLEdBQU1NLGFBQWVOLEdBQU1JLFlBQWNKLEdBQU1DLGlCQUUvQ2xSLEVBQUksRUFBRyw0QkFBNEJxVixTQUc1QixDQUNMRCxTQUNBMWhCLFVBRUgsQ0FBQyxNQUFPb00sR0FPUCxPQU5FbVIsR0FBTUssZUFFSmdCLEdBQ0ZwYyxHQUFLb2UsUUFBUWhDLEdBR1QsSUFBSTFMLEdBQVksNEJBQTRCOUcsRUFBTTlILFdBQVdpUCxTQUNqRW5ILEVBRUgsR0FpQlV3VixHQUFrQixLQUFPLENBQ3BDL2MsSUFBS3JDLEdBQUtxQyxJQUNWQyxJQUFLdEMsR0FBS3NDLElBQ1ZnUSxJQUFLdFMsR0FBS3FmLFVBQVlyZixHQUFLc2YsVUFDM0JDLFVBQVd2ZixHQUFLcWYsVUFDaEJkLEtBQU12ZSxHQUFLc2YsVUFDWEUsUUFBU3hmLEdBQUt5Zix1QkFRVCxTQUFTYixLQUNkLE1BQU12YyxJQUFFQSxFQUFHQyxJQUFFQSxFQUFHZ1EsSUFBRUEsRUFBR2lOLFVBQUVBLEVBQVNoQixLQUFFQSxFQUFJaUIsUUFBRUEsR0FBWUosS0FFcER0VixFQUFJLEVBQUcsMkRBQTJEekgsTUFDbEV5SCxFQUFJLEVBQUcsMkRBQTJEeEgsTUFDbEV3SCxFQUFJLEVBQUcsK0NBQStDd0ksTUFDdER4SSxFQUFJLEVBQUcsNkNBQTZDeVYsTUFDcER6VixFQUFJLEVBQUcsNENBQTRDeVUsTUFDbkR6VSxFQUFJLEVBQUcsMERBQTBEMFYsS0FDbkUsQ0FFQSxJQUFlRSxHQU1iTixHQU5hTSxHQU9ILElBQU0zRSxHQ3BabEIsSUFBSXpjLElBQXFCLEVBZ0JsQixNQUFNcWhCLEdBQWNqUSxNQUFPa1EsRUFBVUMsS0FFMUMvVixFQUFJLEVBQUcsMkNBR1AsTUFBTXRNLEVUeUwwQixFQUFDK1osRUFBZTdJLEVBQWlCLE1BQ2pFLElBQUlsUixFQUFVLENBQUEsRUFzQmQsT0FwQkkrWixFQUFjdUksS0FDaEJ0aUIsRUFBVXFQLEVBQVM2QixHQUNuQmxSLEVBQVFILE9BQU9aLEtBQU84YSxFQUFjOWEsTUFBUThhLEVBQWNsYSxPQUFPWixLQUNqRWUsRUFBUUgsT0FBT1csTUFBUXVaLEVBQWN2WixPQUFTdVosRUFBY2xhLE9BQU9XLE1BQ25FUixFQUFRSCxPQUFPSSxRQUNiOFosRUFBYzlaLFNBQVc4WixFQUFjbGEsT0FBT0ksUUFDaERELEVBQVFzaEIsUUFBVSxDQUNoQmdCLElBQUt2SSxFQUFjdUksTUFHckJ0aUIsRUFBVW9SLEVBQ1JGLEVBQ0E2SSxFQUVBL1UsR0FJSmhGLEVBQVFILE9BQU9JLFFBQ2JELEVBQVFILFFBQVFJLFNBQVcsU0FBU0QsRUFBUUgsUUFBUVosTUFBUSxRQUN2RGUsQ0FBTyxFU2hORXVpQixDQUFtQkgsRUFBVWpSLEtBR3ZDNEksRUFBZ0IvWixFQUFRSCxPQUc5QixHQUFJRyxFQUFRc2hCLFNBQVNnQixLQUErQixLQUF4QnRpQixFQUFRc2hCLFFBQVFnQixJQUMxQyxJQUNFaFcsRUFBSSxFQUFHLGtEQUVQLE1BQU1vVixFQUFTYyxHQ2hDZCxTQUFrQkMsR0FDdkIsTUFBTXpnQixFQUFTLElBQUkwZ0IsRUFBQUEsTUFBTSxJQUFJMWdCLE9BRTdCLE9BRGUyZ0IsRUFBVTNnQixHQUNYNGdCLFNBQVNILEVBQU8sQ0FBRUksU0FBVSxDQUFDLGtCQUM3QyxDRDZCUUQsQ0FBUzVpQixFQUFRc2hCLFFBQVFnQixLQUN6QnRpQixFQUNBcWlCLEdBSUYsUUFERTlFLEdBQU1HLHNCQUNEZ0UsQ0FDUixDQUFDLE1BQU90VixHQUNQLE9BQU9pVyxFQUNMLElBQUluUCxHQUFZLG9DQUFvQ0ssU0FBU25ILEdBRWhFLENBSUgsR0FBSTJOLEVBQWNqYSxRQUFVaWEsRUFBY2phLE9BQU8wRyxPQUUvQyxJQUdFLE9BRkE4RixFQUFJLEVBQUcsb0RBQ1B0TSxFQUFRSCxPQUFPRSxNQUFROE8sRUFBQUEsYUFBYWtMLEVBQWNqYSxPQUFRLFFBQ25EMGlCLEdBQWV4aUIsRUFBUUgsT0FBT0UsTUFBTXVHLE9BQVF0RyxFQUFTcWlCLEVBQzdELENBQUMsTUFBT2pXLEdBQ1AsT0FBT2lXLEVBQ0wsSUFBSW5QLEdBQVkscUNBQXFDSyxTQUFTbkgsR0FFakUsQ0FJSCxHQUNHMk4sRUFBY2hhLE9BQWlDLEtBQXhCZ2EsRUFBY2hhLE9BQ3JDZ2EsRUFBYy9aLFNBQXFDLEtBQTFCK1osRUFBYy9aLFFBRXhDLElBSUUsT0FIQXNNLEVBQUksRUFBRyxrREFHSG9FLEVBQVUxUSxFQUFRYSxhQUFhQyxvQkFDMUJnaUIsR0FBaUI5aUIsRUFBU3FpQixHQUlHLGlCQUF4QnRJLEVBQWNoYSxNQUN4QnlpQixHQUFlekksRUFBY2hhLE1BQU11RyxPQUFRdEcsRUFBU3FpQixHQUNwRFUsR0FDRS9pQixFQUNBK1osRUFBY2hhLE9BQVNnYSxFQUFjL1osUUFDckNxaUIsRUFFUCxDQUFDLE1BQU9qVyxHQUNQLE9BQU9pVyxFQUNMLElBQUluUCxHQUFZLG9DQUFvQ0ssU0FBU25ILEdBRWhFLENBSUgsT0FBT2lXLEVBQ0wsSUFBSW5QLEdBQ0YsaUpBRUgsRUErR1U4UCxHQUFpQmhqQixJQUM1QixNQUFNNlcsTUFBRUEsRUFBS1EsVUFBRUEsR0FDYnJYLEVBQVFILFFBQVFHLFNBQVc0TyxFQUFjNU8sRUFBUUgsUUFBUUUsT0FHckRVLEVBQWdCbU8sRUFBYzVPLEVBQVFILFFBQVFZLGVBR3BELElBQUlELEVBQ0ZSLEVBQVFILFFBQVFXLE9BQ2hCNlcsR0FBVzdXLE9BQ1hDLEdBQWU0VyxXQUFXN1csT0FDMUJSLEVBQVFILFFBQVFRLGNBQ2hCLEVBR0ZHLEVBQVFtYixLQUFLN1csSUFBSSxHQUFLNlcsS0FBSzlXLElBQUlyRSxFQUFPLElBR3RDQSxFVjJJeUIsRUFBQ3hCLEVBQU9pa0IsRUFBWSxLQUM3QyxNQUFNQyxFQUFhdkgsS0FBS3dILElBQUksR0FBSUYsR0FBYSxHQUM3QyxPQUFPdEgsS0FBSzVXLE9BQU8vRixFQUFRa2tCLEdBQWNBLENBQVUsRVU3STNDRSxDQUFZNWlCLEVBQU8sR0FHM0IsTUFBTXdhLEVBQU8sQ0FDWDFhLE9BQ0VOLEVBQVFILFFBQVFTLFFBQ2hCK1csR0FBV2dNLGNBQ1h4TSxHQUFPdlcsUUFDUEcsR0FBZTRXLFdBQVdnTSxjQUMxQjVpQixHQUFlb1csT0FBT3ZXLFFBQ3RCTixFQUFRSCxRQUFRTSxlQUNoQixJQUNGSSxNQUNFUCxFQUFRSCxRQUFRVSxPQUNoQjhXLEdBQVdpTSxhQUNYek0sR0FBT3RXLE9BQ1BFLEdBQWU0VyxXQUFXaU0sYUFDMUI3aUIsR0FBZW9XLE9BQU90VyxPQUN0QlAsRUFBUUgsUUFBUU8sY0FDaEIsSUFDRkksU0FJRixJQUFLLElBQUsraUIsRUFBT3ZrQixLQUFVcUcsT0FBT3VHLFFBQVFvUCxHQUN4Q0EsRUFBS3VJLEdBQ2MsaUJBQVZ2a0IsR0FBc0JBLEVBQU00UixRQUFRLFNBQVUsSUFBTTVSLEVBRS9ELE9BQU9nYyxDQUFJLEVBZ0JQK0gsR0FBVzdRLE1BQU9sUyxFQUFTd2pCLEVBQVduQixFQUFhQyxLQUN2RCxJQUFNemlCLE9BQVFrYSxFQUFlbFosWUFBYTRpQixHQUF1QnpqQixFQUVqRSxNQUFNMGpCLEVBQzZDLGtCQUExQ0QsRUFBbUIzaUIsbUJBQ3RCMmlCLEVBQW1CM2lCLG1CQUNuQkEsR0FFTixHQUFLMmlCLEdBRUUsR0FBSUMsRUFDVCxHQUE2QyxpQkFBbEMxakIsRUFBUWEsWUFBWUssVUFFN0JsQixFQUFRYSxZQUFZSyxVQUFZc04sRUFDOUJ4TyxFQUFRYSxZQUFZSyxVQUNwQndQLEVBQVUxUSxFQUFRYSxZQUFZRSwwQkFFM0IsSUFBS2YsRUFBUWEsWUFBWUssVUFDOUIsSUFDRSxNQUFNQSxFQUFZMk4sRUFBQUEsYUFBYSxpQkFBa0IsUUFDakQ3TyxFQUFRYSxZQUFZSyxVQUFZc04sRUFDOUJ0TixFQUNBd1AsRUFBVTFRLEVBQVFhLFlBQVlFLG9CQUVqQyxDQUFDLE1BQU9xTCxHQUNQUSxFQUNFLEVBQ0FSLEVBQ0EsMERBRUgsT0FyQkhxWCxFQUFxQnpqQixFQUFRYSxZQUFjLEdBNkI3QyxJQUFLNmlCLEdBQTRCRCxFQUFvQixDQUNuRCxHQUNFQSxFQUFtQnhpQixVQUNuQndpQixFQUFtQnZpQixXQUNuQnVpQixFQUFtQnppQixXQUluQixPQUFPcWhCLEVBQ0wsSUFBSW5QLEdBQ0YscUdBTU51USxFQUFtQnhpQixVQUFXLEVBQzlCd2lCLEVBQW1CdmlCLFdBQVksRUFDL0J1aUIsRUFBbUJ6aUIsWUFBYSxDQUNqQyxDQXlDRCxHQXRDSXdpQixJQUNGQSxFQUFVM00sTUFBUTJNLEVBQVUzTSxPQUFTLENBQUEsRUFDckMyTSxFQUFVbk0sVUFBWW1NLEVBQVVuTSxXQUFhLENBQUEsRUFDN0NtTSxFQUFVbk0sVUFBVUMsU0FBVSxHQUdoQ3lDLEVBQWM3WixPQUFTNlosRUFBYzdaLFFBQVUsUUFDL0M2WixFQUFjOWEsS0FBT2lQLEVBQVE2TCxFQUFjOWEsS0FBTThhLEVBQWM5WixTQUNwQyxRQUF2QjhaLEVBQWM5YSxPQUNoQjhhLEVBQWN4WixPQUFRLEdBSXhCLENBQUMsZ0JBQWlCLGdCQUFnQmdGLFNBQVNvZSxJQUN6QyxJQUNNNUosR0FBaUJBLEVBQWM0SixLQUVPLGlCQUEvQjVKLEVBQWM0SixJQUNyQjVKLEVBQWM0SixHQUFhclcsU0FBUyxTQUVwQ3lNLEVBQWM0SixHQUFlL1UsRUFDM0JDLEVBQUFBLGFBQWFrTCxFQUFjNEosR0FBYyxTQUN6QyxHQUdGNUosRUFBYzRKLEdBQWUvVSxFQUMzQm1MLEVBQWM0SixJQUNkLEdBSVAsQ0FBQyxNQUFPdlgsR0FDUDJOLEVBQWM0SixHQUFlLEdBQzdCL1csRUFBYSxFQUFHUixFQUFPLGdCQUFnQnVYLHVCQUN4QyxLQUlDRixFQUFtQjNpQixtQkFDckIsSUFDRTJpQixFQUFtQnppQixXQUFhMlAsRUFDOUI4UyxFQUFtQnppQixXQUNuQnlpQixFQUFtQjFpQixtQkFFdEIsQ0FBQyxNQUFPcUwsR0FDUFEsRUFBYSxFQUFHUixFQUFPLDZDQUN4QixDQUlILEdBQ0VxWCxHQUNBQSxFQUFtQnhpQixVQUNuQndpQixFQUFtQnhpQixVQUFVNlMsUUFBUSxLQUFPLEVBSTVDLEdBQUkyUCxFQUFtQjFpQixtQkFDckIsSUFDRTBpQixFQUFtQnhpQixTQUFXNE4sRUFBWUEsYUFDeEM0VSxFQUFtQnhpQixTQUNuQixPQUVILENBQUMsTUFBT21MLEdBQ1BxWCxFQUFtQnhpQixVQUFXLEVBQzlCMkwsRUFBYSxFQUFHUixFQUFPLDJDQUN4QixNQUVEcVgsRUFBbUJ4aUIsVUFBVyxFQUtsQ2pCLEVBQVFILE9BQVMsSUFDWkcsRUFBUUgsVUFDUm1qQixHQUFjaGpCLElBSW5CLElBS0UsT0FBT3FpQixHQUFZLFFBSkVsQixHQUNuQnBILEVBQWNoRCxRQUFVeU0sR0FBYWxCLEVBQ3JDdGlCLEdBR0gsQ0FBQyxNQUFPb00sR0FDUCxPQUFPaVcsRUFBWWpXLEVBQ3BCLEdBcUJHMFcsR0FBbUIsQ0FBQzlpQixFQUFTcWlCLEtBQ2pDLElBQ0UsSUFBSXRMLEVBQ0FoWCxFQUFRQyxFQUFRSCxPQUFPRSxPQUFTQyxFQUFRSCxPQUFPRyxRQWtCbkQsTUFoQnFCLGlCQUFWRCxJQUVUZ1gsRUFBU2hYLEVBQVE2UCxFQUNmN1AsRUFDQUMsRUFBUWEsYUFBYUMscUJBR3pCaVcsRUFBU2hYLEVBQU0rUCxXQUFXLFlBQWEsSUFBSXhKLE9BR1QsTUFBOUJ5USxFQUFPQSxFQUFPdlEsT0FBUyxLQUN6QnVRLEVBQVNBLEVBQU9wUixVQUFVLEVBQUdvUixFQUFPdlEsT0FBUyxJQUkvQ3hHLEVBQVFILE9BQU9rWCxPQUFTQSxFQUNqQmdNLEdBQVMvaUIsR0FBUyxFQUFPcWlCLEVBQ2pDLENBQUMsTUFBT2pXLEdBQ1AsT0FBT2lXLEVBQ0wsSUFBSW5QLEdBQ0Ysd0NBQXdDbFQsRUFBUUgsUUFBUTBoQixXQUFhLGtKQUNyRWhPLFNBQVNuSCxHQUVkLEdBY0dvVyxHQUFpQixDQUFDb0IsRUFBZ0I1akIsRUFBU3FpQixLQUMvQyxNQUFNdmhCLG1CQUFFQSxHQUF1QmQsRUFBUWEsWUFHdkMsR0FDRStpQixFQUFlOVAsUUFBUSxTQUFXLEdBQ2xDOFAsRUFBZTlQLFFBQVEsVUFBWSxFQUduQyxPQURBeEgsRUFBSSxFQUFHLGlDQUNBeVcsR0FBUy9pQixHQUFTLEVBQU9xaUIsRUFBYXVCLEdBRy9DLElBRUUsTUFBTUMsRUFBWTFVLEtBQUtwRSxNQUFNNlksRUFBZTlULFdBQVcsWUFBYSxNQUdwRSxPQUFPaVQsR0FBUy9pQixFQUFTNmpCLEVBQVd4QixFQUNyQyxDQUFDLE1BQU9qVyxHQUVQLE9BQUlzRSxFQUFVNVAsR0FDTGdpQixHQUFpQjlpQixFQUFTcWlCLEdBRzFCQSxFQUNMLElBQUluUCxHQUNGLGtNQUNBSyxTQUFTbkgsR0FHaEIsR0V6Z0JHMFgsR0FBYyxHQWNQQyxHQUFvQixLQUMvQnpYLEVBQUksRUFBRywrQ0FDUCxJQUFLLE1BQU0yUixLQUFNNkYsR0FDZkUsY0FBYy9GLEVBQ2YsRUN4QkdnRyxHQUFxQixDQUFDN1gsRUFBTzhYLEVBQUtwUixFQUFLcVIsS0FFM0N2WCxFQUFhLEVBQUdSLEdBR1ksZ0JBQXhCdEYsRUFBS3FELHVCQUNBaUMsRUFBTVksTUFJZm1YLEVBQUsvWCxFQUFNLEVBV1BnWSxHQUF3QixDQUFDaFksRUFBTzhYLEVBQUtwUixFQUFLcVIsS0FFOUMsTUFBUTNRLFdBQVk2USxFQUFNQyxPQUFFQSxFQUFNaGdCLFFBQUVBLEVBQU8wSSxNQUFFQSxHQUFVWixFQUNqRG9ILEVBQWE2USxHQUFVQyxHQUFVLElBR3ZDeFIsRUFBSXdSLE9BQU85USxHQUFZK1EsS0FBSyxDQUFFL1EsYUFBWWxQLFVBQVMwSSxTQUFRLEVBRzdELElDakJBd1gsR0FBZSxDQUFDQyxFQUFLQyxLQUNuQixNQUFNQyxFQUNKLHlFQUdJQyxFQUFjLENBQ2xCOWYsSUFBSzRmLEVBQVkzaUIsYUFBZSxHQUNoQ0MsT0FBUTBpQixFQUFZMWlCLFFBQVUsRUFDOUJDLE1BQU95aUIsRUFBWXppQixPQUFTLEVBQzVCQyxXQUFZd2lCLEVBQVl4aUIsYUFBYyxFQUN0Q0MsUUFBU3VpQixFQUFZdmlCLFVBQVcsRUFDaENDLFVBQVdzaUIsRUFBWXRpQixZQUFhLEdBSWxDd2lCLEVBQVkxaUIsWUFDZHVpQixFQUFJbGpCLE9BQU8sZUFJYixNQUFNc2pCLEVBQVVMLEVBQVUsQ0FDeEJNLFNBQStCLEdBQXJCRixFQUFZNWlCLE9BQWMsSUFFcEM4QyxJQUFLOGYsRUFBWTlmLElBRWpCaWdCLFFBQVNILEVBQVkzaUIsTUFDckIraUIsUUFBUyxDQUFDQyxFQUFTOVEsS0FDakJBLEVBQVMrUSxPQUFPLENBQ2RYLEtBQU0sS0FDSnBRLEVBQVNtUSxPQUFPLEtBQUthLEtBQUssQ0FBRTdnQixRQUFTcWdCLEdBQU0sRUFFN0NTLFFBQVMsS0FDUGpSLEVBQVNtUSxPQUFPLEtBQUthLEtBQUtSLEVBQUksR0FFaEMsRUFFSlUsS0FBT0osSUFHcUIsSUFBeEJMLEVBQVl6aUIsVUFDYyxJQUExQnlpQixFQUFZeGlCLFdBQ1o2aUIsRUFBUUssTUFBTTVaLE1BQVFrWixFQUFZemlCLFNBQ2xDOGlCLEVBQVFLLE1BQU1DLGVBQWlCWCxFQUFZeGlCLFlBRTNDa0ssRUFBSSxFQUFHLDJDQUNBLEtBT2JtWSxFQUFJZSxJQUFJWCxHQUVSdlksRUFDRSxFQUNBLDhDQUE4Q3NZLEVBQVk5ZixvQkFBb0I4ZixFQUFZNWlCLDhDQUE4QzRpQixFQUFZMWlCLGNBQ3JKLEVDL0VILE1BQU11akIsV0FBa0J2UyxHQUN0QixXQUFBRSxDQUFZOU8sRUFBU2dnQixHQUNuQmpSLE1BQU0vTyxHQUNOZ1AsS0FBS2dSLE9BQVNoUixLQUFLRSxXQUFhOFEsQ0FDakMsQ0FFRCxTQUFBb0IsQ0FBVXBCLEdBRVIsT0FEQWhSLEtBQUtnUixPQUFTQSxFQUNQaFIsSUFDUixFQ29CSCxNQUFNcVMsR0FBZSxDQUNuQkMsSUFBSyxZQUNMQyxLQUFNLGFBQ05DLElBQUssWUFDTHpJLElBQUssa0JBQ0xpRixJQUFLLGlCQUlQLElBQUl5RCxHQUFrQixFQUd0QixNQUFNQyxHQUFnQixHQUdoQkMsR0FBZSxHQWdCZkMsR0FBYyxDQUFDQyxFQUFXbEIsRUFBUzlRLEVBQVVsRixLQUNqRCxJQUFJeVMsR0FBUyxFQUNiLE1BQU16RCxHQUFFQSxFQUFFbUksU0FBRUEsRUFBUW5uQixLQUFFQSxFQUFJcWMsS0FBRUEsR0FBU3JNLEVBY3JDLE9BWkFrWCxFQUFVMVEsTUFBTXhVLElBQ2QsR0FBSUEsRUFBVSxDQUNaLElBQUlvbEIsRUFBZXBsQixFQUFTZ2tCLEVBQVM5USxFQUFVOEosRUFBSW1JLEVBQVVubkIsRUFBTXFjLEdBTW5FLFlBSnFCMVYsSUFBakJ5Z0IsSUFBK0MsSUFBakJBLElBQ2hDM0UsRUFBUzJFLElBR0osQ0FDUixLQUdJM0UsQ0FBTSxFQWFUNEUsR0FBZ0JwVSxNQUFPK1MsRUFBUzlRLEVBQVVnUSxLQUM5QyxJQUVFLE1BQU1vQyxFQUFjMVYsSUFHZHVWLEVBQVdsSSxFQUFBQSxLQUFPdE4sUUFBUSxLQUFNLElBR2hDb0gsRUFBaUI3RyxJQUVqQm1LLEVBQU8ySixFQUFRM0osS0FDZjJDLElBQU84SCxHQUViLElBQUk5bUIsRUFBT2lQLEVBQVFvTixFQUFLcmMsTUFHeEIsSUFBS3FjLEdoQm1IUyxpQkFEWXRNLEVnQmxIQ3NNLEtoQm9INUIvTCxNQUFNQyxRQUFRUixJQUNOLE9BQVRBLEdBQzZCLElBQTdCM0osT0FBT0MsS0FBSzBKLEdBQU14SSxPZ0JySGQsTUFBTSxJQUFJaWYsR0FDUixzSkFDQSxLQUtKLElBQUkxbEIsRUFBUTZPLEVBQWMwTSxFQUFLeGIsUUFBVXdiLEVBQUt0YixTQUFXc2IsRUFBS3JNLE1BRzlELElBQUtsUCxJQUFVdWIsRUFBS2dILElBUWxCLE1BUEFoVyxFQUNFLEVBQ0EsdUJBQXVCOFosVUFDckJuQixFQUFRdUIsUUFBUSxvQkFBc0J2QixFQUFRd0IsV0FBV0Msa0RBQ3RCdlgsS0FBS0MsVUFBVWtNLE9BR2hELElBQUltSyxHQUNSLG9RQUNBLEtBSUosSUFBSVksR0FBZSxFQVduQixHQVJBQSxFQUFlSCxHQUFZRixHQUFlZixFQUFTOVEsRUFBVSxDQUMzRDhKLEtBQ0FtSSxXQUNBbm5CLE9BQ0FxYyxVQUltQixJQUFqQitLLEVBQ0YsT0FBT2xTLEVBQVNnUixLQUFLa0IsR0FHdkIsSUFBSU0sR0FBb0IsRUFHeEIxQixFQUFRMkIsT0FBTzdULEdBQUcsU0FBUyxLQUN6QjRULEdBQW9CLENBQUksSUFHMUJyYSxFQUFJLEVBQUcsaURBQWlEOFosTUFFeEQ5SyxFQUFLcGIsT0FBaUMsaUJBQWhCb2IsRUFBS3BiLFFBQXVCb2IsRUFBS3BiLFFBQVcsUUFHbEUsTUFBTW1TLEVBQWlCLENBQ3JCeFMsT0FBUSxDQUNORSxRQUNBZCxPQUNBaUIsT0FBUW9iLEVBQUtwYixPQUFPLEdBQUcybUIsY0FBZ0J2TCxFQUFLcGIsT0FBTzRtQixPQUFPLEdBQzFEeG1CLE9BQVFnYixFQUFLaGIsT0FDYkMsTUFBTythLEVBQUsvYSxNQUNaQyxNQUFPOGEsRUFBSzlhLE9BQVN3WCxFQUFlblksT0FBT1csTUFDM0NDLGNBQWVtTyxFQUFjME0sRUFBSzdhLGVBQWUsR0FDakRDLGFBQWNrTyxFQUFjME0sRUFBSzVhLGNBQWMsSUFFakRHLFlBQWEsQ0FDWEMsbUJOc1htQ0EsR01yWG5DQyxvQkFBb0IsRUFDcEJHLFVBQVcwTixFQUFjME0sRUFBS3BhLFdBQVcsR0FDekNELFNBQVVxYSxFQUFLcmEsU0FDZkQsV0FBWXNhLEVBQUt0YSxhQUlqQmpCLElBRUZzUyxFQUFleFMsT0FBT0UsTUFBUTZQLEVBQzVCN1AsRUFDQXNTLEVBQWV4UixZQUFZQyxxQkFLL0IsTUFBTWQsRUFBVW9SLEVBQW1CNEcsRUFBZ0IzRixHQWNuRCxHQVhBclMsRUFBUUgsT0FBT0csUUFBVUQsRUFHekJDLEVBQVFzaEIsUUFBVSxDQUNoQmdCLElBQUtoSCxFQUFLZ0gsTUFBTyxFQUNqQnlFLElBQUt6TCxFQUFLeUwsTUFBTyxFQUNqQkMsV0FBWTFMLEVBQUswTCxhQUFjLEVBQy9CekYsVUFBVzZFLEdBSVQ5SyxFQUFLZ0gsS2hCaUN5QixDQUFDdFQsR0FDZixDQUNwQixtREFDQSx1RUFDQSx3RUFDQSx1RkFDQSxxRUFHbUJ5RyxNQUFNd1IsR0FBWUEsRUFBUWhnQixLQUFLK0gsS2dCMUNsQ2tZLENBQXVCbG5CLEVBQVFzaEIsUUFBUWdCLEtBQ3JELE1BQU0sSUFBSW1ELEdBQ1IsNktBQ0EsV0FLRXRELEdBQVluaUIsR0FBUyxDQUFDb00sRUFBTythLEtBYWpDLEdBWEFsQyxFQUFRMkIsT0FBT1EsbUJBQW1CLFNBRzlCcFAsRUFBZTFXLE9BQU9LLGNBQ3hCMkssRUFDRSxFQUNBLCtCQUErQjhaLDBDQUFpREcsVUFLaEZJLEVBQ0YsT0FBT3JhLEVBQ0wsRUFDQSxtRkFLSixHQUFJRixFQUNGLE1BQU1BLEVBSVIsSUFBSythLElBQVNBLEVBQUt6RixPQUNqQixNQUFNLElBQUkrRCxHQUNSLG9HQUFvR1csb0JBQTJCZSxFQUFLekYsVUFDcEksS0FVSixPQUxBemlCLEVBQU9rb0IsRUFBS25uQixRQUFRSCxPQUFPWixLQUczQmluQixHQUFZRCxHQUFjaEIsRUFBUzlRLEVBQVUsQ0FBRThKLEtBQUkzQyxLQUFNNkwsRUFBS3pGLFNBRTFEeUYsRUFBS3pGLE9BRUhwRyxFQUFLeUwsSUFFTSxRQUFUOW5CLEdBQTBCLE9BQVJBLEVBQ2JrVixFQUFTZ1IsS0FDZGtDLE9BQU9DLEtBQUtILEVBQUt6RixPQUFRLFFBQVFqVixTQUFTLFdBSXZDMEgsRUFBU2dSLEtBQUtnQyxFQUFLekYsU0FJNUJ2TixFQUFTb1QsT0FBTyxlQUFnQjVCLEdBQWExbUIsSUFBUyxhQUdqRHFjLEVBQUswTCxZQUNSN1MsRUFBU3FULFdBQ1AsR0FBR3ZDLEVBQVF3QyxPQUFPQyxVQUFZekMsRUFBUTNKLEtBQUtvTSxVQUFZLFdBQ3JEem9CLEdBQVEsU0FNRSxRQUFUQSxFQUNIa1YsRUFBU2dSLEtBQUtnQyxFQUFLekYsUUFDbkJ2TixFQUFTZ1IsS0FBS2tDLE9BQU9DLEtBQUtILEVBQUt6RixPQUFRLGlCQTVCN0MsQ0E2QkMsR0FFSixDQUFDLE1BQU90VixHQUNQK1gsRUFBSy9YLEVBQ04sQ2hCN0QwQixJQUFDNEMsQ2dCNkQzQixFQ3BRSCxNQUFNMlksR0FBVXhZLEtBQUtwRSxNQUFNOEQsRUFBWUEsYUFBQytZLEVBQU1wakIsS0FBQytJLEVBQVcsa0JBRXBEc2EsR0FBa0IsSUFBSXJiLEtBRXRCc2IsR0FBZSxHQXVDTixTQUFTQyxHQUFnQnRELEdBQ3RDLElBQUtBLEVBQ0gsT0FBTyxFTDVDZ0IsSUFBQ3hHLElLeUIxQitKLGFBQVksS0FDVixNQUFNekssRUFBUS9hLEtBQ1J5bEIsRUFDcUIsSUFBekIxSyxFQUFNRSxlQUNGLEVBQ0NGLEVBQU1DLGlCQUFtQkQsRUFBTUUsZUFBa0IsSUFFeERxSyxHQUFhek4sS0FBSzROLEdBQ2RILEdBQWF0aEIsT0E1QkYsSUE2QmJzaEIsR0FBYTlWLE9BQ2QsR0EvQmtCLEtMSHJCOFIsR0FBWXpKLEtBQUs0RCxHS2tEakJ3RyxFQUFJNVIsSUFBSSxXQUFXLENBQUNxVixFQUFHcFYsS0FDckIsTUFBTXlLLEVBQVEvYSxLQUNSMmxCLEVBQVNMLEdBQWF0aEIsT0FDdEI0aEIsRUF4Q0lOLEdBQWFPLFFBQU8sQ0FBQ0MsRUFBR0MsSUFBTUQsRUFBSUMsR0FBRyxHQUNwQ1QsR0FBYXRoQixPQXlDeEI4RixFQUFJLEVBQUcsNERBRVB3RyxFQUFJcVMsS0FBSyxDQUNQYixPQUFRLEtBQ1JrRSxTQUFVWCxHQUNWWSxPQUNFOU0sS0FBSytNLFFBQ0YsSUFBSWxjLE1BQU80UixVQUFZeUosR0FBZ0J6SixXQUFhLElBQU8sSUFDMUQsV0FDTmhmLFFBQVN1b0IsR0FBUXZvQixRQUNqQnVwQixrQkFBbUJsVixLQUNuQm1WLHNCQUF1QnJMLEVBQU1NLGFBQzdCTCxpQkFBa0JELEVBQU1DLGlCQUN4QnFMLGNBQWV0TCxFQUFNSyxlQUNyQkgsZUFBZ0JGLEVBQU1FLGVBQ3RCcUwsWUFBY3ZMLEVBQU1DLGlCQUFtQkQsRUFBTUUsZUFBa0IsSUFFL0RqYixLQUFNQSxLQUdOMmxCLFNBQ0FDLGdCQUNBOWpCLFFBQVMsUUFBUTZqQixtQ0FBd0NDLEVBQWNXLFFBQVEsT0FHL0VDLGtCQUFtQnpMLEVBQU1HLHNCQUN6QnVMLG1CQUFvQjFMLEVBQU1DLGlCQUFtQkQsRUFBTUcsdUJBQ25ELEdBRU4sQ0N6RUEsTUFBTXdMLEdBQWdCLElBQUlDLElBR3BCMUUsR0FBTTJFLElBR1ozRSxHQUFJNEUsUUFBUSxnQkFHWjVFLEdBQUllLElBQUk4RCxLQUdSLE1BQU1DLEdBQVVDLEVBQU9DLGdCQUNqQkMsR0FBU0YsRUFBTyxDQUNwQkQsV0FDQUksT0FBUSxDQUNOQyxVQUFXLFlBS2ZuRixHQUFJZSxJQUFJNEQsRUFBUTdFLEtBQUssQ0FBRXNGLE1BQU8sWUFDOUJwRixHQUFJZSxJQUFJNEQsRUFBUVUsV0FBVyxDQUFFQyxVQUFVLEVBQU1GLE1BQU8sWUFHcERwRixHQUFJZSxJQUFJa0UsR0FBT00sUUFPZixNQUFNQyxHQUE2QjNvQixJQUNqQ0EsRUFBT3lSLEdBQUcsZUFBZ0IzRyxJQUN4QlEsRUFBYSxFQUFHUixFQUFPLDBCQUEwQkEsRUFBTTlILFVBQVUsSUFHbkVoRCxFQUFPeVIsR0FBRyxTQUFVM0csSUFDbEJRLEVBQWEsRUFBR1IsRUFBTywwQkFBMEJBLEVBQU05SCxVQUFVLElBR25FaEQsRUFBT3lSLEdBQUcsY0FBZTZULElBQ3ZCQSxFQUFPN1QsR0FBRyxTQUFVM0csSUFDbEJRLEVBQWEsRUFBR1IsRUFBTywwQkFBMEJBLEVBQU05SCxVQUFVLEdBQ2pFLEdBQ0YsRUFhUzRsQixHQUFjaFksTUFBT2lZLElBQ2hDLElBRUUsSUFBS0EsRUFBYTVvQixPQUNoQixPQUFPLEVBSVQsSUFBSzRvQixFQUFhOW5CLElBQUlDLE1BQU8sQ0FFM0IsTUFBTThuQixFQUFhelgsRUFBSzBYLGFBQWE1RixJQUdyQ3dGLEdBQTBCRyxHQUcxQkEsRUFBV0UsT0FBT0gsRUFBYXpvQixLQUFNeW9CLEVBQWExb0IsTUFHbER5bkIsR0FBY3FCLElBQUlKLEVBQWF6b0IsS0FBTTBvQixHQUVyQzlkLEVBQ0UsRUFDQSxtQ0FBbUM2ZCxFQUFhMW9CLFFBQVEwb0IsRUFBYXpvQixRQUV4RSxDQUdELEdBQUl5b0IsRUFBYTluQixJQUFJZCxPQUFRLENBRTNCLElBQUltSyxFQUFLOGUsRUFFVCxJQUVFOWUsUUFBWStlLEVBQUFBLFNBQVdDLFNBQ3JCQyxFQUFBQSxNQUFNbm1CLEtBQUsybEIsRUFBYTluQixJQUFJRSxTQUFVLGNBQ3RDLFFBSUZpb0IsUUFBYUMsRUFBQUEsU0FBV0MsU0FDdEJDLEVBQUFBLE1BQU1ubUIsS0FBSzJsQixFQUFhOW5CLElBQUlFLFNBQVUsY0FDdEMsT0FFSCxDQUFDLE1BQU82SixHQUNQRSxFQUNFLEVBQ0EscURBQXFENmQsRUFBYTluQixJQUFJRSxzREFFekUsQ0FFRCxHQUFJbUosR0FBTzhlLEVBQU0sQ0FFZixNQUFNSSxFQUFjbFksRUFBTTJYLGFBQWEsQ0FBRTNlLE1BQUs4ZSxRQUFRL0YsSUFHdER3RixHQUEwQlcsR0FHMUJBLEVBQVlOLE9BQU9ILEVBQWE5bkIsSUFBSVgsS0FBTXlvQixFQUFhMW9CLE1BR3ZEeW5CLEdBQWNxQixJQUFJSixFQUFhOW5CLElBQUlYLEtBQU1rcEIsR0FFekN0ZSxFQUNFLEVBQ0Esb0NBQW9DNmQsRUFBYTFvQixRQUFRMG9CLEVBQWE5bkIsSUFBSVgsUUFFN0UsQ0FDRixDQUlDeW9CLEVBQWFyb0IsY0FDYnFvQixFQUFhcm9CLGFBQWFQLFNBQ3pCLENBQUMsRUFBR3NwQixLQUFLcGxCLFNBQVMwa0IsRUFBYXJvQixhQUFhQyxjQUU3Q3lpQixHQUFVQyxHQUFLMEYsRUFBYXJvQixjQUk5QjJpQixHQUFJZSxJQUFJNEQsRUFBUTBCLE9BQU9ILEVBQUFBLE1BQU1ubUIsS0FBSytJLEVBQVcsWUFHN0N3ZCxHQUFZdEcsSUY0R0QsQ0FBQ0EsSUFJZEEsRUFBSXVHLEtBQUssSUFBSzFFLElBTWQ3QixFQUFJdUcsS0FBSyxhQUFjMUUsR0FBYyxFRXJIbkMyRSxDQUFheEcsSUM5SkYsQ0FBQ0EsTUFDYkEsR0FFR0EsRUFBSTVSLElBQUksS0FBSyxDQUFDb1MsRUFBUzlRLEtBQ3JCQSxFQUFTK1csU0FBUzFtQixFQUFJQSxLQUFDK0ksRUFBVyxTQUFVLGNBQWMsR0FDMUQsRUQwSko0ZCxDQUFRMUcsSUUzSkcsQ0FBQ0EsTUFDYkEsR0FFR0EsRUFBSXVHLEtBQ0YsK0JBQ0E5WSxNQUFPK1MsRUFBUzlRLEVBQVVnUSxLQUN4QixJQUNFLE1BQU1pSCxFQUFhdGtCLEVBQUtXLHVCQUd4QixJQUFLMmpCLElBQWVBLEVBQVc1a0IsT0FDN0IsTUFBTSxJQUFJaWYsR0FDUix1R0FDQSxLQUtKLE1BQU00RixFQUFRcEcsRUFBUXBTLElBQUksV0FDMUIsSUFBS3dZLEdBQVNBLElBQVVELEVBQ3RCLE1BQU0sSUFBSTNGLEdBQ1IsaUVBQ0EsS0FLSixNQUFNMVAsRUFBYWtQLEVBQVF3QyxPQUFPMVIsV0FDbEMsSUFBSUEsRUFtQkYsTUFBTSxJQUFJMFAsR0FBVSwyQkFBNEIsS0FsQmhELFVBRVFoUyxHQUFvQnNDLEVBQzNCLENBQUMsTUFBTzNKLEdBQ1AsTUFBTSxJQUFJcVosR0FDUixtQkFBbUJyWixFQUFNOUgsVUFDekI4SCxFQUFNb0gsWUFDTkQsU0FBU25ILEVBQ1osQ0FHRCtILEVBQVNtUSxPQUFPLEtBQUthLEtBQUssQ0FDeEIzUixXQUFZLElBQ1pwVSxRQUFTcVUsS0FDVG5QLFFBQVMsK0NBQStDeVIsTUFNN0QsQ0FBQyxNQUFPM0osR0FDUCtYLEVBQUsvWCxFQUNOLElBRUosRUZ1R0hrZixDQUFhN0csSUw1SUYsQ0FBQ0EsSUFFZEEsRUFBSWUsSUFBSXZCLElBR1JRLEVBQUllLElBQUlwQixHQUFzQixFSzBJNUJtSCxDQUFhOUcsR0FDZCxDQUFDLE1BQU9yWSxHQUNQLE1BQU0sSUFBSThHLEdBQ1Isc0RBQ0FLLFNBQVNuSCxFQUNaLEdBTVVvZixHQUFlLEtBQzFCbGYsRUFBSSxFQUFHLGlDQUNQLElBQUssTUFBTzVLLEVBQU1KLEtBQVc0bkIsR0FDM0I1bkIsRUFBT3VkLE9BQU0sS0FDWHFLLEdBQWN1QyxPQUFPL3BCLEdBQ3JCNEssRUFBSSxFQUFHLG1DQUFtQzVLLEtBQVEsR0FFckQsRUE2REgsSUFBZUosR0FBQSxDQUNiNG9CLGVBQ0FzQixnQkFDQUUsV0F4RHdCLElBQU14QyxHQXlEOUJ5QyxtQkFsRGlDakgsR0FBZ0JGLEdBQVVDLEdBQUtDLEdBbURoRWtILFdBNUN3QixJQUFNeEMsRUE2QzlCeUMsT0F0Q29CLElBQU1wSCxHQXVDMUJlLElBL0JpQixDQUFDNU0sS0FBU2tULEtBQzNCckgsR0FBSWUsSUFBSTVNLEtBQVNrVCxFQUFZLEVBK0I3QmpaLElBdEJpQixDQUFDK0YsS0FBU2tULEtBQzNCckgsR0FBSTVSLElBQUkrRixLQUFTa1QsRUFBWSxFQXNCN0JkLEtBYmtCLENBQUNwUyxLQUFTa1QsS0FDNUJySCxHQUFJdUcsS0FBS3BTLEtBQVNrVCxFQUFZLEdHN096QixNQUFNQyxHQUFrQjdaLE1BQU84WixVQUU5QjFaLFFBQVEyWixXQUFXLENBRXZCbEksS0FHQXlILEtBR0EzSyxPQUlGN1YsUUFBUWtoQixLQUFLRixFQUFTLEVDNEV4QixJQUFlRyxHQUFBLENBRWI3cUIsVUFDQTRvQixlQUdBa0MsV0FwQ2lCbGEsTUFBT2xTLEladWRXLElBQUNoQixFWTVicEMsT1o0Ym9DQSxFWXBkbENnQixFQUFRYSxhQUFlYixFQUFRYSxZQUFZQyxtQlpxZDdDQSxHQUFxQjRQLEVBQVUxUixHWGhVTixDQUFDa0UsSUFFMUJnSyxFQUFZaEssR0FBVzBjLFNBQVMxYyxFQUFRQyxRQUdwQ0QsR0FBV0EsRUFBUUcsTUFDckI4SixFQUNFakssRUFBUUcsS0FDUkgsRUFBUUUsTUFBUSwrQkFFbkIsRXVCM0pEaXBCLENBQVlyc0IsRUFBUWtELFNBR2hCbEQsRUFBUXdELE1BQU1FLHVCQW5EbEI0SSxFQUFJLEVBQUcsc0RBR1B0QixRQUFRK0gsR0FBRyxRQUFTdVosSUFDbEJoZ0IsRUFBSSxFQUFHLDRCQUE0QmdnQixLQUFRLElBSTdDdGhCLFFBQVErSCxHQUFHLFVBQVViLE1BQU83TixFQUFNaW9CLEtBQ2hDaGdCLEVBQUksRUFBRyxPQUFPakksc0JBQXlCaW9CLFlBQ2pDUCxHQUFnQixFQUFFLElBSTFCL2dCLFFBQVErSCxHQUFHLFdBQVdiLE1BQU83TixFQUFNaW9CLEtBQ2pDaGdCLEVBQUksRUFBRyxPQUFPakksc0JBQXlCaW9CLFlBQ2pDUCxHQUFnQixFQUFFLElBSTFCL2dCLFFBQVErSCxHQUFHLFVBQVViLE1BQU83TixFQUFNaW9CLEtBQ2hDaGdCLEVBQUksRUFBRyxPQUFPakksc0JBQXlCaW9CLFlBQ2pDUCxHQUFnQixFQUFFLElBSTFCL2dCLFFBQVErSCxHQUFHLHFCQUFxQmIsTUFBTzlGLEVBQU8vSCxLQUM1Q3VJLEVBQWEsRUFBR1IsRUFBTyxPQUFPL0gsa0JBQ3hCMG5CLEdBQWdCLEVBQUUsV0E0QnBCNVcsR0FBb0JuVixTQUdwQjhlLEdBQVMsQ0FDYnRjLEtBQU14QyxFQUFRd0MsTUFBUSxDQUNwQkMsV0FBWSxFQUNaQyxXQUFZLEdBRWRxYyxjQUFlL2UsRUFBUWxCLFVBQVVDLE1BQVEsS0FJcENpQixDQUFPLEVBVWR1c0IsYVprRjBCcmEsTUFBT2xTLElBRWpDQSxFQUFRSCxPQUFPRSxNQUFRQyxFQUFRSCxPQUFPRSxPQUFTQyxFQUFRSCxPQUFPRyxjQUd4RG1pQixHQUFZbmlCLEdBQVNrUyxNQUFPOUYsRUFBTythLEtBRXZDLEdBQUkvYSxFQUNGLE1BQU1BLEVBR1IsTUFBTW5NLFFBQUVBLEVBQU9oQixLQUFFQSxHQUFTa29CLEVBQUtubkIsUUFBUUgsT0FHdkNxVixFQUFhQSxjQUNYalYsR0FBVyxTQUFTaEIsSUFDWCxRQUFUQSxFQUFpQm9vQixPQUFPQyxLQUFLSCxFQUFLekYsT0FBUSxVQUFZeUYsRUFBS3pGLGNBSXZEYixJQUFVLEdBQ2hCLEVZdEdGMkwsWVpvQnlCdGEsTUFBT2xTLElBQ2hDLE1BQU15c0IsRUFBaUIsR0FHdkIsSUFBSyxJQUFJQyxLQUFRMXNCLEVBQVFILE9BQU9jLE1BQU15RixNQUFNLEtBQzFDc21CLEVBQU9BLEVBQUt0bUIsTUFBTSxLQUNFLElBQWhCc21CLEVBQUtsbUIsUUFDUGltQixFQUFlcFMsS0FDYjhILEdBQ0UsSUFDS25pQixFQUNISCxPQUFRLElBQ0hHLEVBQVFILE9BQ1hDLE9BQVE0c0IsRUFBSyxHQUNienNCLFFBQVN5c0IsRUFBSyxNQUdsQixDQUFDdGdCLEVBQU8rYSxLQUVOLEdBQUkvYSxFQUNGLE1BQU1BLEVBSVI4SSxFQUFhQSxjQUNYaVMsRUFBS25uQixRQUFRSCxPQUFPSSxRQUNTLFFBQTdCa25CLEVBQUtubkIsUUFBUUgsT0FBT1osS0FDaEJvb0IsT0FBT0MsS0FBS0gsRUFBS3pGLE9BQVEsVUFDekJ5RixFQUFLekYsT0FDVixLQU9YLFVBRVFwUCxRQUFRd0MsSUFBSTJYLFNBR1o1TCxJQUNQLENBQUMsTUFBT3pVLEdBQ1AsTUFBTSxJQUFJOEcsR0FDUixrREFDQUssU0FBU25ILEVBQ1osR1lqRUQrVixlQUdBckQsWUFDQStCLFlBR0FwSyxXckJqRndCLENBQUNVLEVBQWFwWSxLQUVsQ0EsR0FBTXlILFNBRVIwSyxFQTZOSixTQUF3Qm5TLEdBRXRCLE1BQU00dEIsRUFBYzV0QixFQUFLNnRCLFdBQ3RCQyxHQUFrQyxlQUExQkEsRUFBSWpjLFFBQVEsS0FBTSxNQUk3QixHQUFJK2IsR0FBZSxHQUFLNXRCLEVBQUs0dEIsRUFBYyxHQUFJLENBQzdDLE1BQU1HLEVBQVcvdEIsRUFBSzR0QixFQUFjLEdBQ3BDLElBRUUsR0FBSUcsR0FBWUEsRUFBU3hmLFNBQVMsU0FFaEMsT0FBTzZCLEtBQUtwRSxNQUFNOEQsZUFBYWllLEdBRWxDLENBQUMsTUFBTzFnQixHQUNQUSxFQUNFLEVBQ0FSLEVBQ0Esc0RBQXNEMGdCLFVBRXpELENBQ0YsQ0FHRCxNQUFPLEVBQ1QsQ0F2UHFCQyxDQUFlaHVCLElBSWxDd1MsR0FBb0IxUyxFQUFlcVMsR0FHbkNBLEVBQWlCUyxHQUFZOVMsR0FHekJzWSxJQUVGakcsRUFBaUJFLEVBQ2ZGLEVBQ0FpRyxFQUNBblMsSUFLQWpHLEdBQU15SCxTQUVSMEssRUErUkosU0FBMkJsUixFQUFTakIsRUFBTUYsR0FDeEMsSUFBSW11QixHQUFZLEVBQ2hCLElBQUssSUFBSTNjLEVBQUksRUFBR0EsRUFBSXRSLEVBQUt5SCxPQUFRNkosSUFBSyxDQUNwQyxNQUFNMUUsRUFBUzVNLEVBQUtzUixHQUFHTyxRQUFRLEtBQU0sSUFHL0JxYyxFQUFrQmhvQixFQUFXMEcsR0FDL0IxRyxFQUFXMEcsR0FBUXZGLE1BQU0sS0FDekIsR0FHSixJQUFJOG1CLEVBQ0pELEVBQWdCNUUsUUFBTyxDQUFDbGpCLEVBQUs4UyxFQUFNa1UsS0FDN0JjLEVBQWdCem1CLE9BQVMsSUFBTTJsQixJQUNqQ2UsRUFBZS9uQixFQUFJOFMsR0FBTWhaLE1BRXBCa0csRUFBSThTLEtBQ1ZwWixHQUVIb3VCLEVBQWdCNUUsUUFBTyxDQUFDbGpCLEVBQUs4UyxFQUFNa1UsS0FDN0JjLEVBQWdCem1CLE9BQVMsSUFBTTJsQixRQUVSLElBQWRobkIsRUFBSThTLEtBQ1RsWixJQUFPc1IsR0FDWSxZQUFqQjZjLEVBQ0YvbkIsRUFBSThTLEdBQVF2SCxFQUFVM1IsRUFBS3NSLElBQ0QsV0FBakI2YyxFQUNUL25CLEVBQUk4UyxJQUFTbFosRUFBS3NSLEdBQ1Q2YyxFQUFhcFosUUFBUSxNQUFRLEVBQ3RDM08sRUFBSThTLEdBQVFsWixFQUFLc1IsR0FBR2pLLE1BQU0sS0FFMUJqQixFQUFJOFMsR0FBUWxaLEVBQUtzUixJQUduQi9ELEVBQ0UsRUFDQSxtQ0FBbUNYLHlDQUVyQ3FoQixHQUFZLElBSVg3bkIsRUFBSThTLEtBQ1ZqWSxFQUNKLENBR0dndEIsR0FDRmpkLElBR0YsT0FBTy9QLENBQ1QsQ0FuVnFCbXRCLENBQWtCamMsRUFBZ0JuUyxFQUFNRixJQUlwRHFTLEdxQm9EUDZhLG1CQUdBemYsTUFDQU0sZUFDQU0sY0FDQUMsb0JBR0FpZ0IsZXJCNkM2QkMsSUFDN0IsTUFBTWhjLEVBQWEsQ0FBQSxFQUVuQixJQUFLLE1BQU8zRixFQUFLMU0sS0FBVXFHLE9BQU91RyxRQUFReWhCLEdBQWEsQ0FDckQsTUFBTUosRUFBa0Job0IsRUFBV3lHLEdBQU96RyxFQUFXeUcsR0FBS3RGLE1BQU0sS0FBTyxHQUd2RTZtQixFQUFnQjVFLFFBQ2QsQ0FBQ2xqQixFQUFLOFMsRUFBTWtVLElBQ1RobkIsRUFBSThTLEdBQ0hnVixFQUFnQnptQixPQUFTLElBQU0ybEIsRUFBUW50QixFQUFRbUcsRUFBSThTLElBQVMsSUFDaEU1RyxFQUVILENBQ0QsT0FBT0EsQ0FBVSxFcUIxRGpCaWMsYXJCbEQwQnBiLE1BQU9xYixJQUVqQyxJQUFJQyxFQUFhLENBQUEsRUFHYnhoQixFQUFBQSxXQUFXdWhCLEtBQ2JDLEVBQWFyZSxLQUFLcEUsTUFBTThELEVBQVlBLGFBQUMwZSxFQUFnQixVQUl2RCxNQXdETTVvQixFQUFVVSxPQUFPQyxLQUFLbEIsR0FBZWlDLEtBQUtvbkIsSUFBWSxDQUMxRGxpQixNQUFPLEdBQUdraUIsWUFDVnp1QixNQUFPeXVCLE1BSVQsT0FBT0MsRUFDTCxDQUNFenVCLEtBQU0sY0FDTm9GLEtBQU0sV0FDTkMsUUFBUywyQ0FDVE0sS0FBTSx5REFDTkYsYUFBYyxHQUNkQyxXQUVGLENBQUVncEIsU0F2RWF6YixNQUFPMGIsRUFBR0MsS0FDekIsSUFBSUMsRUFBbUIsRUFDbkJDLEVBQWUsR0FHbkIsSUFBSyxNQUFNQyxLQUFXSCxFQUVwQnpwQixFQUFjNHBCLEdBQVc1cEIsRUFBYzRwQixHQUFTM25CLEtBQUtzRixJQUFZLElBQzVEQSxFQUNIcWlCLGNBSUZELEVBQWUsSUFBSUEsS0FBaUIzcEIsRUFBYzRwQixJQXVDcEQsYUFwQ01OLEVBQVFLLEVBQWMsQ0FDMUJKLFNBQVV6YixNQUFPK2IsRUFBUUMsS0FnQnZCLEdBZG9CLGtCQUFoQkQsRUFBTzVwQixNQUNUNnBCLEVBQVNBLEVBQU8xbkIsT0FDWjBuQixFQUFPN25CLEtBQUs4bkIsR0FBV0YsRUFBT3RwQixRQUFRd3BCLEtBQ3RDRixFQUFPdHBCLFFBRVg2b0IsRUFBV1MsRUFBT0QsU0FBU0MsRUFBTzVwQixNQUFRNnBCLEdBRTFDVixFQUFXUyxFQUFPRCxTQUFXbmMsR0FDM0J4TSxPQUFPNE0sT0FBTyxHQUFJdWIsRUFBV1MsRUFBT0QsVUFBWSxJQUNoREMsRUFBTzVwQixLQUFLK0IsTUFBTSxLQUNsQjZuQixFQUFPdHBCLFFBQVVzcEIsRUFBT3RwQixRQUFRdXBCLEdBQVVBLEtBSXhDSixJQUFxQkMsRUFBYXZuQixPQUFRLENBQzlDLFVBQ1Fpa0IsRUFBVTJELFNBQUNDLFVBQ2ZkLEVBQ0FwZSxLQUFLQyxVQUFVb2UsRUFBWSxLQUFNLEdBQ2pDLE9BRUgsQ0FBQyxNQUFPcGhCLEdBQ1BRLEVBQ0UsRUFDQVIsRUFDQSxpREFBaURtaEIsVUFFcEQsQ0FDRCxPQUFPLENBQ1IsTUFJRSxDQUFJLEdBb0JaLEVxQi9CRGUsVXRCOEt3QjNxQixJQUV4QixNQUFNNHFCLEVBQWlCcGYsS0FBS3BFLE1BQzFCOEQsRUFBQUEsYUFBYXJLLEVBQUlBLEtBQUMrSSxFQUFXLGtCQUM3Qm5PLFFBR0V1RSxFQUNGMEksUUFBUUMsSUFBSSxzQ0FBc0NpaUIsUUFLcERsaUIsUUFBUUMsSUFDTnVDLEVBQVlBLGFBQUN0QixFQUFZLG9CQUFvQmQsV0FBV3VELEtBQUtDLE9BQzdELElBQUlzZSxNQUFtQnZlLEtBQ3hCLEVzQjdMREQifQ== +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;const b={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},w={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:b.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:b.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:b.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},E={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:w.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:w.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:w.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:w.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:w.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:w.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${w.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${w.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:w.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:w.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:w.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:w.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:w.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:w.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:w.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:w.server.host.value},{type:"number",name:"port",message:"Server port",initial:w.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:w.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:w.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:w.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:w.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:w.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:w.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:w.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:w.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:w.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:w.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:w.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:w.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:w.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:w.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:w.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:w.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:w.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:w.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:w.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:w.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:w.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:w.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:w.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:w.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:w.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:w.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:w.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:w.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:w.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:w.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:w.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:w.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:w.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:w.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:w.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:w.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:w.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:w.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:w.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:w.debug.debuggingPort.value}]},T=["options","globalOptions","themeOptions","resources","payload"],S={},x=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?x(o,`${t}.${r}`):(S[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(S[o.legacyName]=`${t}.${r}`.substring(1)))}}))};x(w),i.config();const R=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),L=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),_=()=>s.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),k=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),I=()=>s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),C=s.z.object({HIGHCHARTS_VERSION:s.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:s.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:R(b.core),HIGHCHARTS_MODULE_SCRIPTS:R(b.modules),HIGHCHARTS_INDICATOR_SCRIPTS:R(b.indicators),HIGHCHARTS_FORCE_FETCH:L(),HIGHCHARTS_CACHE_PATH:_(),HIGHCHARTS_ADMIN_TOKEN:_(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:k(),EXPORT_DEFAULT_WIDTH:k(),EXPORT_DEFAULT_SCALE:k(),EXPORT_RASTERIZATION_TIMEOUT:I(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:L(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:L(),SERVER_ENABLE:L(),SERVER_HOST:_(),SERVER_PORT:k(),SERVER_BENCHMARKING:L(),SERVER_PROXY_HOST:_(),SERVER_PROXY_PORT:k(),SERVER_PROXY_TIMEOUT:I(),SERVER_RATE_LIMITING_ENABLE:L(),SERVER_RATE_LIMITING_MAX_REQUESTS:I(),SERVER_RATE_LIMITING_WINDOW:I(),SERVER_RATE_LIMITING_DELAY:I(),SERVER_RATE_LIMITING_TRUST_PROXY:L(),SERVER_RATE_LIMITING_SKIP_KEY:_(),SERVER_RATE_LIMITING_SKIP_TOKEN:_(),SERVER_SSL_ENABLE:L(),SERVER_SSL_FORCE:L(),SERVER_SSL_PORT:k(),SERVER_SSL_CERT_PATH:_(),POOL_MIN_WORKERS:I(),POOL_MAX_WORKERS:I(),POOL_WORK_LIMIT:k(),POOL_ACQUIRE_TIMEOUT:I(),POOL_CREATE_TIMEOUT:I(),POOL_DESTROY_TIMEOUT:I(),POOL_IDLE_TIMEOUT:I(),POOL_CREATE_RETRY_INTERVAL:I(),POOL_REAPER_INTERVAL:I(),POOL_BENCHMARKING:L(),LOGGING_LEVEL:s.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:_(),LOGGING_DEST:_(),UI_ENABLE:L(),UI_ROUTE:_(),OTHER_NODE_ENV:O(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:L(),OTHER_NO_LOGO:L(),OTHER_HARD_RESET_PAGE:L(),DEBUG_ENABLE:L(),DEBUG_HEADLESS:L(),DEBUG_DEVTOOLS:L(),DEBUG_LISTEN_TO_CONSOLE:L(),DEBUG_DUMPIO:L(),DEBUG_SLOW_MO:I(),DEBUG_DEBUGGING_PORT:k()}).partial().parse(process.env),A=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:A[0]},{title:"warning",color:A[1]},{title:"notice",color:A[2]},{title:"verbose",color:A[3]},{title:"benchmark",color:A[4]}],listeners:[]};for(const[e,t]of Object.entries(w.logging))N[e]=t.value;const P=(t,r)=>{N.toFile&&(N.pathCreated||(!e.existsSync(N.dest)&&e.mkdirSync(N.dest),N.pathCreated=!0),e.appendFile(`${N.dest}${N.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},H=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=N;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;N.listeners.forEach((e=>{e(s,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,s)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=N;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[e-1].color]].concat([o[A[e-1]],"\n",a])),N.listeners.forEach((e=>{e(n,l.join(" "))})),P(l,n)},U=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},D=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},j=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),G=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},F=(t=!1,r)=>{const o=["js","css","files"];let i=t,s=!1;if(r&&t.endsWith(".json"))try{i=M(e.readFileSync(t,"utf8"))}catch(e){return $(2,e,"[cli] No resources found.")}else i=M(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?s||(s=!0):delete i[e];return s?(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 M(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const q=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=q(e[r]));return t},W=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function V(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const B=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,X=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&X(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let K={};const J=()=>K,Y=(e,t,r=[])=>{const o=q(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:Y(o[e],s,r);var i;return o};function Q(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?Q(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in C&&void 0!==C[i.envLink]&&(i.value=C[i.envLink]))}))}function Z(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:Z(o);return t}function ee(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ee(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function te(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class re extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const oe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ie=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),se=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const i=await te(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new re(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return H(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ne=async(t,o,i)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||oe.cdnURL;H(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return oe.sources=await(async(e,t,o,i,s)=>{let n;const a=i.host,l=i.port;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new re("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:C.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>se(`${e}`,c,s,!0))),...t.map((e=>se(`${e}`,c,s))),...o.map((e=>se(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,o,l),oe.hcVersion=ie(oe),e.writeFileSync(i,oe.sources),l}catch(e){throw new re("[cache] Unable to update the local Highcharts cache.").setError(e)}},ae=async r=>{const{highcharts:o,server:i}=r,s=t.join(j,o.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||o.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),n=await ne(o,i.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:s,moduleScripts:c,indicatorScripts:p}=o,u=s.length+c.length+p.length;r.version!==o.version?(H(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(H(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return H(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await ne(o,i.proxy,l):(H(3,"[cache] Dependency cache is up to date, proceeding."),oe.sources=e.readFileSync(l,"utf8"),n=r.modules,oe.hcVersion=ie(oe))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};oe.activeManifest=i,H(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(j,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new re("[cache] Error writing the cache manifest.").setError(e)}})(o,n)},le=()=>t.join(j,J().highcharts.cachePath),ce=()=>oe.hcVersion;function pe(){Highcharts.animObject=function(){return{duration:0}}}async function ue(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&s(u),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const he=e.readFileSync(j+"/templates/template.html","utf8");let de;async function ge(){if(!de)return!1;const e=await de.newPage();return await e.setCacheEnabled(!1),await fe(e),function(e){const{debug:t}=J();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function me(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function fe(e){await e.setContent(he,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${le()}/sources.js`}),await e.evaluate(pe)}const ve=async(e,t,r,o)=>e.evaluate(ue,t,r,o);var ye=async(r,o,i)=>{let s=[];try{H(4,"[export] Determining export path.");const n=i.export,a=n?.options?.chart?.displayErrors&&oe.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===n.type)return o;l=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else H(4,"[export] Treating as config."),n.strInj?await ve(r,{chart:{height:n.height,width:n.width}},i,a):(o.chart.height=n.height,o.chart.width=n.width,await ve(r,o,i,a));s=await async function(r,o){const i=[],s=o.customLogic.resources;if(s){const n=[];if(s.js&&n.push({content:s.js}),s.files)for(const t of s.files){const r=!t.startsWith("http");n.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of n)try{i.push(await r.addScriptTag(e))}catch(e){$(2,e,"[export] The JS resource cannot be loaded.")}n.length=0;const a=[];if(s.css){let e=s.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")?a.push({url:r}):o.customLogic.allowFileResources&&a.push({path:t.join(j,r)}));a.push({content:s.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){$(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(r,i);const c=l?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.ceil(c.chartHeight||n.height),u=Math.ceil(c.chartWidth||n.width),{x:h,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let g;if(await r.setViewport({height:p,width:u,deviceScaleFactor:l?1:parseFloat(n.scale)}),"svg"===n.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(n.type))g=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout"))),i||1500)))]))(r,n.type,"base64",{width:u,height:p,x:h,y:d},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new re(`[export] Unsupported output format ${n.type}.`);g=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout"))),i||1500)))])))(r,p,u,"base64",n.rasterizationTimeout)}return await me(r,s),g}catch(e){return await me(r,s),e}};let be=!1;const we={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ee={};const Te={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new re("The page is invalid or closed.");H(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new re("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Ee.workLimit/2))}},validate:async e=>!(Ee.workLimit&&++e.workCount>Ee.workLimit)||(H(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ee.workLimit}).`),!1),destroy:async e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Se=async e=>{if(Ee=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=J().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!de){let e=0;const r=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),de=await u.launch(o)}catch(t){if($(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;H(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&H(3,"[browser] Launched browser in debug mode.")}catch(e){throw new re("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!de)throw new re("[browser] Cannot find a browser to open.")}return de}(e.puppeteerArgs),H(3,`[pool] Initializing pool with workers: min ${Ee.minWorkers}, max ${Ee.maxWorkers}.`),be)return H(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ee.minWorkers)>parseInt(Ee.maxWorkers)&&(Ee.minWorkers=Ee.maxWorkers);try{be=new c.Pool({...Te,min:parseInt(Ee.minWorkers),max:parseInt(Ee.maxWorkers),acquireTimeoutMillis:Ee.acquireTimeout,createTimeoutMillis:Ee.createTimeout,destroyTimeoutMillis:Ee.destroyTimeout,idleTimeoutMillis:Ee.idleTimeout,createRetryIntervalMillis:Ee.createRetryInterval,reapIntervalMillis:Ee.reaperInterval,propagateCreateError:!1}),be.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await fe(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){$(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),H(4,`[pool] Releasing a worker with ID ${e.id}.`)})),be.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{be.release(e)})),H(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new re("[pool] Could not create the pool of workers.").setError(e)}};async function xe(){if(H(3,"[pool] Killing pool with all workers and closing browser."),be){for(const e of be.used)be.release(e.resource);be.destroyed||(await be.destroy(),H(4,"[browser] Destroyed the pool of resources."))}await async function(){de?.connected&&await de.close(),H(4,"[browser] Closed the browser.")}()}const Re=async(e,t)=>{let r;try{if(H(4,"[pool] Work received, starting to process."),++we.exportAttempts,Ee.benchmarking&&Oe(),!be)throw new re("Work received, but pool has not been started.");const o=z();try{H(4,"[pool] Acquiring a worker handle."),r=await be.acquire().promise,t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(H(4,"[pool] Acquired a worker handle."),!r.page)throw new re("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=z(),n=await ye(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),be.release(r);const a=(new Date).getTime()-i;return we.timeSpent+=a,we.spentAverage=we.timeSpent/++we.performedExports,H(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++we.droppedExports,r&&be.release(r),new re(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Le=()=>({min:be.min,max:be.max,all:be.numFree()+be.numUsed(),available:be.numFree(),used:be.numUsed(),pending:be.numPendingAcquires()});function Oe(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Le();H(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(5,`[pool] The number of all created resources: ${r}.`),H(5,`[pool] The number of available resources: ${o}.`),H(5,`[pool] The number of acquired resources: ${i}.`),H(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var _e=Le,ke=()=>we;let Ie=!1;const Ce=async(t,r)=>{H(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=q(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Y(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,J()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{H(4,"[chart] Attempting to export from a SVG input.");const e=He(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++we.exportFromSvgAttempts,e}catch(e){return r(new re("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return H(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),He(o.export.instr.trim(),o,r)}catch(e){return r(new re("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return H(4,"[chart] Attempting to export from a raw input."),B(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?He(i.instr.trim(),o,r):Ne(o,i.instr||i.options,r)}catch(e){return r(new re("[chart] Error loading raw input.").setError(e))}return r(new re("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ae=e=>{const{chart:t,exporting:r}=e.export?.options||M(e.export?.instr),o=M(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ne=async(t,r,o,i)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ie;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=F(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=F(r,B(t.customLogic.allowFileResources))}catch(e){$(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new re("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=G(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=M(e.readFileSync(s[t],"utf8"),!0):s[t]=M(s[t],!0))}catch(e){s[t]={},$(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=X(n.customCode,n.allowFileResources)}catch(e){$(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,$(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...Ae(t)};try{return o(!1,await Re(s.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=W(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ne(e,!1,t)}catch(r){return t(new re(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},He=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),Ne(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ne(t,o,r)}catch(e){return B(o)?Pe(t,r):r(new re("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},$e=[],Ue=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of $e)clearInterval(e)},De=(e,t,r,o)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,o(e)},je=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ge=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(H(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),H(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Fe extends re{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Me=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=C.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Fe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Fe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Fe("No new version supplied.",400);try{await(async e=>{const t=J();t?.highcharts&&(t.highcharts.version=e),await ae(t)})(i)}catch(e){throw new Fe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ce(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let We=0;const Ve=[],Be=[],Xe=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},ze=async(e,t,r)=>{try{const r=z(),i=p.v4().replace(/-/g,""),s=J(),n=e.body,a=++We;let l=G(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Fe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=M(n.infile||n.options||n.data);if(!c&&!n.svg)throw H(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Fe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Xe(Ve,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),H(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:M(n.globalOptions,!0),themeOptions:M(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:M(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=W(c,d.customLogic.allowCodeExecution));const g=Y(s,d);if(g.export.options=c,g.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Fe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ce(g,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&H(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return H(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Fe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Xe(Be,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",qe[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const Ke=JSON.parse(e.readFileSync(t.join(j,"package.json"))),Je=new Date,Ye=[];function Qe(e){if(!e)return!1;var t;t=setInterval((()=>{const e=ke(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ye.push(t),Ye.length>30&&Ye.shift()}),6e4),$e.push(t),e.get("/health",((e,t)=>{const r=ke(),o=Ye.length,i=Ye.reduce(((e,t)=>e+t),0)/Ye.length;H(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Je,uptime:Math.floor(((new Date).getTime()-Je.getTime())/1e3/60)+" minutes",version:Ke.version,highchartsVersion:ce(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:_e(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const Ze=new Map,et=m();et.disable("x-powered-by"),et.use(g());const tt=f.memoryStorage(),rt=f({storage:tt,limits:{fieldSize:52428800}});et.use(m.json({limit:52428800})),et.use(m.urlencoded({extended:!0,limit:52428800})),et.use(rt.none());const ot=e=>{e.on("clientError",(e=>{$(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{$(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{$(1,e,`[server] Socket error: ${e.message}`)}))}))},it=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(et);ot(e),e.listen(r.port,r.host),Ze.set(r.port,e),H(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){H(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},et);ot(e),e.listen(r.ssl.port,r.host),Ze.set(r.ssl.port,e),H(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ge(et,r.rateLimiting),et.use(m.static(t.posix.join(j,"public"))),Qe(et),(e=>{e.post("/",ze),e.post("/:filename",ze)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(j,"public","index.html"))}))})(et),Me(et),(e=>{e.use(De),e.use(je)})(et)}catch(e){throw new re("[server] Could not configure and start the server.").setError(e)}},st=()=>{H(4,"[server] Closing all servers.");for(const[e,t]of Ze)t.close((()=>{Ze.delete(e),H(4,`[server] Closed server on port: ${e}.`)}))};var nt={startServer:it,closeServers:st,getServers:()=>Ze,enableRateLimiting:e=>Ge(et,e),getExpress:()=>m,getApp:()=>et,use:(e,...t)=>{et.use(e,...t)},get:(e,...t)=>{et.get(e,...t)},post:(e,...t)=>{et.post(e,...t)}};const at=async e=>{await Promise.allSettled([Ue(),st(),xe()]),process.exit(e)};var lt={server:nt,startServer:it,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=B(t),(e=>{U(e&&parseInt(e.level)),e&&e.dest&&D(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(H(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{H(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("SIGTERM",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("SIGHUP",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("uncaughtException",(async(e,t)=>{$(1,e,`The ${t} error.`),await at(1)}))),await ae(e),await Se({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await xe()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await xe()}catch(e){throw new re("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Se,killPool:xe,setOptions:(t,r)=>(r?.length&&(K=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){$(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Q(w,K),K=Z(w),t&&(K=Y(K,t,T)),r?.length&&(K=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=B(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(H(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&V();return e}(K,r,w)),K),shutdownCleanUp:at,log:H,logWithStack:$,setLogLevel:U,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=S[r]?S[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(E).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,s)=>{let n=0,a=[];for(const e of s)E[e]=E[e].map((t=>({...t,section:e}))),a=[...a,...E[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=ee(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){$(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(j,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(j+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:V};module.exports=lt; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIGEgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgc2VudCBmcm9tIHRoZSBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xyXG5cclxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xyXG5cclxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZSxcclxuICBoaWdoY2hhcnRzLFxyXG4gIHZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cclxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xyXG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XHJcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsICd1dGY4Jyk7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpLmRlYnVnO1xyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogJ3NoZWxsJyxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWcpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIHNldFBhZ2VFdmVudHMocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKCFwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXHJcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcclxuICogYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXHJcbiAqIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcclxuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxyXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAvLyBleHBvcnRzXHJcbiAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xyXG4gICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICBdKSB7XHJcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXHJcbiAqL1xyXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cclxuICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcclxuICBwYWdlLFxyXG4gIGhlaWdodCxcclxuICB3aWR0aCxcclxuICBlbmNvZGluZyxcclxuICByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4pID0+IHtcclxuICBhd2FpdCBwYWdlLmVtdWxhdGVNZWRpYVR5cGUoJ3NjcmVlbicpO1xyXG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5wZGYoe1xyXG4gICAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgZW5jb2RpbmdcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcclxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxyXG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxyXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCksIHtcclxuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcclxuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNoYXJ0OiB7XHJcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzID0gYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XHJcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcclxuICBleHBvcnRBdHRlbXB0czogMCxcclxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXHJcbiAgdGltZVNwZW50OiAwLFxyXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxyXG4gIHNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKiovXHJcblxyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXHJcbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXHJcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XHJcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRJbnRlcnZhbCxcclxuICBjbGVhckFsbEludGVydmFsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlVmVyc2lvbiwgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogdmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCB7IHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgIHJlcy5zZW5kKHtcclxuICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICB1cHRpbWU6XHJcbiAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IHZlcnNpb24oKSxcclxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXHJcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXHJcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxyXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXHJcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFBvb2xcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInJlY3Vyc2l2ZVByb3BzIiwib2JqZWN0VG9VcGRhdGUiLCJuZXN0ZWROYW1lcyIsInNoaWZ0IiwiYXNzaWduIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJGdW5jdGlvbiIsImNoYXJ0IiwiYW5pbWF0aW9uIiwic3RySW5qIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50IiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJwdXBwZXRlZXJFeHBvcnQiLCJleHBvcnRPcHRpb25zIiwiZGVidWdnZXIiLCJpc1NWRyIsInN2Z1RlbXBsYXRlIiwiaW5qZWN0ZWRKcyIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImluamVjdGVkQ3NzIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJhZGRQYWdlUmVzb3VyY2VzIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIm91dGVySFRNTCIsImNyZWF0ZVNWRyIsImVuY29kaW5nIiwiY2xpcCIsInJhY2UiLCJzY3JlZW5zaG90IiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwiY3JlYXRlUERGIiwic3RhdHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJleHBvcnRGcm9tU3ZnQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInBvb2xDb25maWciLCJmYWN0b3J5IiwiY3JlYXRlIiwiaWQiLCJ1dWlkIiwic3RhcnREYXRlIiwiZ2V0VGltZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImhhcmRSZXNldCIsImdvdG8iLCJjbGVhclBhZ2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImNvbm5lY3RlZCIsImNsb3NlQnJvd3NlciIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsImdldFBvb2xJbmZvSlNPTiIsIm51bUZyZWUiLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwicGVuZGluZyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiQUREX1RBR1MiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwiZXhwb3J0Um91dGVzIiwic2VuZEZpbGUiLCJ1aVJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImVuYWJsZVJhdGVMaW1pdGluZyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiYWxsU2V0dGxlZCIsImV4aXQiLCJpbmRleCIsImluaXRFeHBvcnQiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSxjQUNBLHVCQUNBLGdCQUVBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 2a83a136..c0557975 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as r,appendFile as o,readFileSync as i,promises as s,writeFileSync as n}from"fs";import a,{join as l,posix as c}from"path";import{HttpsProxyAgent as p}from"https-proxy-agent";import h from"prompts";import u from"dotenv";import{z as d}from"zod";import*as g from"url";import{fileURLToPath as m}from"url";import f from"http";import v from"https";import{Pool as y}from"tarn";import{v4 as b}from"uuid";import w from"puppeteer";import{JSDOM as E}from"jsdom";import T from"dompurify";import S from"cors";import x from"express";import R from"multer";import L from"express-rate-limit";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},_={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},k={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:_.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:_.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:_.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:_.debug.debuggingPort.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},A=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?A(o,`${t}.${r}`):(C[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(C[o.legacyName]=`${t}.${r}`.substring(1)))}}))};A(_),u.config();const N=e=>d.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>d.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),H=e=>d.enum([...e,""]).transform((e=>""!==e?e:void 0)),$=()=>d.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),U=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=()=>d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=d.object({HIGHCHARTS_VERSION:d.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:d.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:N(O.core),HIGHCHARTS_MODULE_SCRIPTS:N(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:N(O.indicators),HIGHCHARTS_FORCE_FETCH:P(),HIGHCHARTS_CACHE_PATH:$(),HIGHCHARTS_ADMIN_TOKEN:$(),EXPORT_TYPE:H(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:H(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:D(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:$(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:$(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:D(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:D(),SERVER_RATE_LIMITING_WINDOW:D(),SERVER_RATE_LIMITING_DELAY:D(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:$(),SERVER_RATE_LIMITING_SKIP_TOKEN:$(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:$(),POOL_MIN_WORKERS:D(),POOL_MAX_WORKERS:D(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:D(),POOL_CREATE_TIMEOUT:D(),POOL_DESTROY_TIMEOUT:D(),POOL_IDLE_TIMEOUT:D(),POOL_CREATE_RETRY_INTERVAL:D(),POOL_REAPER_INTERVAL:D(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:d.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:$(),LOGGING_DEST:$(),UI_ENABLE:P(),UI_ROUTE:$(),OTHER_NODE_ENV:H(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:D(),DEBUG_DEBUGGING_PORT:U()}).partial().parse(process.env),j=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:j[0]},{title:"warning",color:j[1]},{title:"notice",color:j[2]},{title:"verbose",color:j[3]},{title:"benchmark",color:j[4]}],listeners:[]};for(const[e,t]of Object.entries(_.logging))M[e]=t.value;const F=(e,i)=>{M.toFile&&(M.pathCreated||(!t(M.dest)&&r(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)})))},W=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=M;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;M.listeners.forEach((e=>{e(s,r.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(r)),F(r,s)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=M;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([o[j[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),F(l,n)},q=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},B=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return W(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},X=m(new URL("../.",import.meta.url)),K=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},J=(e=!1,t)=>{const r=["js","css","files"];let o=e,s=!1;if(t&&e.endsWith(".json"))try{o=z(i(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else o=z(e),o&&!t&&delete o.files;for(const e in o)r.includes(e)?s||(s=!0):delete o[e];return s?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):W(3,"[cli] No resources found.")};function z(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const Y=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=Y(e[r]));return t},Q=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Z(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const ee=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,te=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&te(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},re=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const ie=()=>oe,se=(e,t,r=[])=>{const o=Y(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:se(o[e],s,r);var i;return o};function ne(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ne(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in G&&void 0!==G[i.envLink]&&(i.value=G[i.envLink]))}))}function ae(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ae(o);return t}function le(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=le(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ce(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?v:f)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class pe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const he={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ue=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),de=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),W(4,`[cache] Fetching script - ${e}.js`);const i=await ce(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new pe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return W(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ge=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||he.cdnURL;W(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return he.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new p({host:n,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},c=[...e.map((e=>de(`${e}`,l,i,!0))),...t.map((e=>de(`${e}`,l,i))),...r.map((e=>de(`${e}`,l)))];return(await Promise.all(c)).join(";\n")})([...e.coreScripts.map((e=>`${s}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${s}maps/${i}modules/${e}`:`${s}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${s}stock/${i}indicators/${e}`))],e.customScripts,t,a),he.hcVersion=ue(he),n(r,he.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},me=async e=>{const{highcharts:o,server:s}=e,a=l(X,o.cachePath);let c;const p=l(a,"manifest.json"),h=l(a,"sources.js");if(!t(a)&&r(a),!t(p)||o.forceFetch)W(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ge(o,s.proxy,h);else{let e=!1;const t=JSON.parse(i(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=o,l=r.length+n.length+a.length;t.version!==o.version?(W(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(W(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(n||[]).some((e=>{if(!t.modules[e])return W(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ge(o,s.proxy,h):(W(3,"[cache] Dependency cache is up to date, proceeding."),he.sources=i(h,"utf8"),c=t.modules,he.hcVersion=ue(he))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};he.activeManifest=r,W(3,"[cache] Writing a new manifest.");try{n(l(X,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(o,c)},fe=()=>l(X,ie().highcharts.cachePath);var ve=async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)},ye=()=>he,be=()=>he.hcVersion;function we(){Highcharts.animObject=function(){return{duration:0}}}function Ee(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&s(h),Highcharts[t.export.constr||"chart"]("container",c,p);const u=o();for(const e in u)"function"!=typeof u[e]&&delete u[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const Te=g.fileURLToPath(new URL(".",import.meta.url)),Se=e.readFileSync(Te+"/../templates/template.html","utf8");let xe;async function Re(){if(!xe)return!1;const e=await xe.newPage();return await e.setCacheEnabled(!1),await Le(e),e}async function Le(e){await e.setContent(Se,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(we)}const Oe=g.fileURLToPath(new URL(".",import.meta.url)),_e=(e,t,r,o)=>e.evaluate(Ee,t,r,o);var ke=async(e,t,r)=>{const o=[],s=async e=>{for(const e of o)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))};try{W(4,"[export] Determining export path.");const n=r.export,l=n?.options?.chart?.displayErrors&&ye().activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(W(4,"[export] Treating as SVG."),"svg"===n.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else W(4,"[export] Treating as config."),n.strInj?await _e(e,{chart:{height:n.height,width:n.width}},r,l):(t.chart.height=n.height,t.chart.width=n.width,await _e(e,t,r,l));const p=r.customLogic.resources;if(p){const t=[];if(p.js&&t.push({content:p.js}),p.files)for(const e of p.files){const r=!e.startsWith("http");t.push(r?{content:i(e,"utf8")}:{url:e})}for(const r of t)try{o.push(await e.addScriptTag(r))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}t.length=0;const s=[];if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let e of t)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?s.push({url:e}):r.customLogic.allowFileResources&&s.push({path:a.join(Oe,e)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of s)try{o.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const h=c?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),u=Math.ceil(h.chartHeight||n.height),d=Math.ceil(h.chartWidth||n.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let f;if(await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))f=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))]))(e,n.type,"base64",{width:d,height:u,x:g,y:m},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);f=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))])))(e,u,d,"base64",n.rasterizationTimeout)}return await s(e),f}catch(t){return await s(e),t}};let Ie=!1;const Ce={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ae={};const Ne={create:async()=>{let e=!1;const t=b(),r=(new Date).getTime();try{if(e=await Re(),!e||e.isClosed())throw new pe("The page is invalid or closed.");W(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new pe("Error encountered when creating a new page.").setError(e)}const{debug:o}=ie();return o.enable&&o.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),{id:t,page:e,workCount:Math.round(Math.random()*(Ae.workLimit/2))}},validate:async e=>!(Ae.workLimit&&++e.workCount>Ae.workLimit)||(W(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ae.workLimit}).`),!1),destroy:async e=>{W(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Pe=async e=>{if(Ae=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=ie().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!xe){let e=0;const r=async()=>{try{W(3,`[browser] Attempting to get a browser instance (try ${++e}).`),xe=await w.launch(o)}catch(t){if(V(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;W(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&W(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!xe)throw new pe("[browser] Cannot find a browser to open.")}return xe}(e.puppeteerArgs),W(3,`[pool] Initializing pool with workers: min ${Ae.minWorkers}, max ${Ae.maxWorkers}.`),Ie)return W(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ae.minWorkers)>parseInt(Ae.maxWorkers)&&(Ae.minWorkers=Ae.maxWorkers);try{Ie=new y({...Ne,min:parseInt(Ae.minWorkers),max:parseInt(Ae.maxWorkers),acquireTimeoutMillis:Ae.acquireTimeout,createTimeoutMillis:Ae.createTimeout,destroyTimeoutMillis:Ae.destroyTimeout,idleTimeoutMillis:Ae.idleTimeout,createRetryIntervalMillis:Ae.createRetryInterval,reapIntervalMillis:Ae.reaperInterval,propagateCreateError:!1}),Ie.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Le(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),W(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ie.on("destroySuccess",((e,t)=>{W(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ie.release(e)})),W(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new pe("[pool] Could not create the pool of workers.").setError(e)}};async function He(){if(W(3,"[pool] Killing pool with all workers and closing browser."),Ie){for(const e of Ie.used)Ie.release(e.resource);Ie.destroyed||(await Ie.destroy(),W(4,"[browser] Destroyed the pool of resources."))}await async function(){xe?.connected&&await xe.close(),W(4,"[browser] Closed the browser.")}()}const $e=async(e,t)=>{let r;try{if(W(4,"[pool] Work received, starting to process."),++Ce.exportAttempts,Ae.benchmarking&&De(),!Ie)throw new pe("Work received, but pool has not been started.");const o=re();try{W(4,"[pool] Acquiring a worker handle."),r=await Ie.acquire().promise,t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(W(4,"[pool] Acquired a worker handle."),!r.page)throw new pe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();W(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=re(),n=await ke(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await Re()),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&W(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ie.release(r);const a=(new Date).getTime()-i;return Ce.timeSpent+=a,Ce.spentAverage=Ce.timeSpent/++Ce.performedExports,W(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ce.droppedExports,r&&Ie.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ue=()=>({min:Ie.min,max:Ie.max,all:Ie.numFree()+Ie.numUsed(),available:Ie.numFree(),used:Ie.numUsed(),pending:Ie.numPendingAcquires()});function De(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ue();W(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),W(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),W(5,`[pool] The number of all created resources: ${r}.`),W(5,`[pool] The number of available resources: ${o}.`),W(5,`[pool] The number of acquired resources: ${i}.`),W(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Ge=Ue,je=()=>Ce;let Me=!1;const Fe=async(e,t)=>{W(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=Y(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=se(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),o=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{W(4,"[chart] Attempting to export from a SVG input.");const e=Be(function(e){const t=new E("").window;return T(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++Ce.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return W(4,"[chart] Attempting to export from an input file."),r.export.instr=i(o.infile,"utf8"),Be(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return W(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?qe(r,t):"string"==typeof o.instr?Be(o.instr.trim(),r,t):Ve(r,o.instr||o.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.").setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},We=e=>{const{chart:t,exporting:r}=e.export?.options||z(e.export?.instr),o=z(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ve=async(e,t,r,o)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Me;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=i("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=K(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=z(i(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=te(n.customCode,n.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=i(n.callback,"utf8")}catch(e){n.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...We(e)};try{return r(!1,await $e(s.strInj||t||o,e))}catch(e){return r(e)}},qe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Q(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ve(e,!1,t)}catch(r){return t(new pe(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Be=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return W(4,"[chart] Parsing input as SVG."),Ve(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ve(t,o,r)}catch(e){return ee(o)?qe(t,r):r(new pe("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Xe=[],Ke=()=>{W(4,"[server] Clearing all registered intervals.");for(const e of Xe)clearInterval(e)},Je=(e,t,r,o)=>{V(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,o(e)},ze=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ye=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=L({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(W(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),W(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Qe extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let et=0;const tt=[],rt=[],ot=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},it=async(e,t,r)=>{try{const r=re(),i=b().replace(/-/g,""),s=ie(),n=e.body,a=++et;let l=K(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Qe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw W(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Qe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=ot(tt,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),W(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:Me,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Q(c,u.customLogic.allowCodeExecution));const d=se(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Qe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&W(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return W(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Qe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ot(rt,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const st=JSON.parse(i(l(X,"package.json"))),nt=new Date,at=[];function lt(e){if(!e)return!1;var t;t=setInterval((()=>{const e=je(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;at.push(t),at.length>30&&at.shift()}),6e4),Xe.push(t),e.get("/health",((e,t)=>{const r=je(),o=at.length,i=at.reduce(((e,t)=>e+t),0)/at.length;W(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:nt,uptime:Math.floor(((new Date).getTime()-nt.getTime())/1e3/60)+" minutes",version:st.version,highchartsVersion:be(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Ge(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const ct=new Map,pt=x();pt.disable("x-powered-by"),pt.use(S());const ht=R.memoryStorage(),ut=R({storage:ht,limits:{fieldSize:52428800}});pt.use(x.json({limit:52428800})),pt.use(x.urlencoded({extended:!0,limit:52428800})),pt.use(ut.none());const dt=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},gt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=f.createServer(pt);dt(t),t.listen(e.port,e.host),ct.set(e.port,t),W(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await s.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await s.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){W(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=v.createServer({key:t,cert:r},pt);dt(o),o.listen(e.ssl.port,e.host),ct.set(e.ssl.port,o),W(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(pt,e.rateLimiting),pt.use(x.static(c.join(X,"public"))),lt(pt),(e=>{e.post("/",it),e.post("/:filename",it)})(pt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(X,"public","index.html"))}))})(pt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=G.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Qe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Qe("No new version supplied.",400);try{await ve(i)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:be(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}))})(pt),(e=>{e.use(Je),e.use(ze)})(pt)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},mt=()=>{W(4,"[server] Closing all servers.");for(const[e,t]of ct)t.close((()=>{ct.delete(e),W(4,`[server] Closed server on port: ${e}.`)}))};var ft={startServer:gt,closeServers:mt,getServers:()=>ct,enableRateLimiting:e=>Ye(pt,e),getExpress:()=>x,getApp:()=>pt,use:(e,...t)=>{pt.use(e,...t)},get:(e,...t)=>{pt.get(e,...t)},post:(e,...t)=>{pt.post(e,...t)}};const vt=async e=>{await Promise.allSettled([Ke(),mt(),He()]),process.exit(e)};var yt={server:ft,startServer:gt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Me=ee(t),(e=>{q(e&&parseInt(e.level)),e&&e.dest&&B(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(W(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{W(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGTERM",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("SIGHUP",(async(e,t)=>{W(4,`The ${e} event with code: ${t}.`),await vt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await vt(1)}))),await me(e),await Pe({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Fe(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;n(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await He()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Fe({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await He()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,initPool:Pe,killPool:He,setOptions:(e,t)=>(t?.length&&(oe=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(i(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ne(_,oe),oe=ae(_),e&&(oe=se(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=ee(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(W(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:vt,log:W,logWithStack:V,setLogLevel:q,enableFileLogging:B,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(i(e,"utf8")));const o=Object.keys(k).map((e=>({title:`${e} options`,value:e})));return h({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:o},{onSubmit:async(t,o)=>{let i=0,n=[];for(const e of o)k[e]=k[e].map((t=>({...t,section:e}))),n=[...n,...k[e]];return await h(n,{onSubmit:async(t,o)=>{if("moduleScripts"===t.name?(o=o.length?o.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=o):r[t.section]=le(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[o]:o),++i===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){V(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(i(l(X,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(i(X+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{yt as default}; +import"colors";import{existsSync as e,mkdirSync as t,appendFile as r,readFileSync as o,promises as i,writeFileSync as s}from"fs";import n,{join as a,posix as l}from"path";import{HttpsProxyAgent as c}from"https-proxy-agent";import p from"prompts";import h from"dotenv";import{z as u}from"zod";import{fileURLToPath as d}from"url";import g from"http";import m from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import y from"puppeteer";import{JSDOM as b}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import x from"express-rate-limit";const R={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","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","flowmap"],indicators:["indicators-all"]},L={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:R.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:R.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:R.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{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 custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},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). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},O={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:L.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:L.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:L.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:L.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:L.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:L.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${L.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${L.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:L.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:L.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:L.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:L.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:L.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:L.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:L.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:L.server.host.value},{type:"number",name:"port",message:"Server port",initial:L.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:L.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:L.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:L.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:L.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:L.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:L.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:L.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:L.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:L.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:L.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:L.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:L.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:L.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:L.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:L.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:L.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:L.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:L.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:L.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:L.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:L.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:L.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:L.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:L.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:L.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:L.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:L.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:L.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:L.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:L.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:L.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:L.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:L.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:L.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:L.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:L.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:L.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:L.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:L.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:L.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:L.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?I(o,`${t}.${r}`):(k[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(k[o.legacyName]=`${t}.${r}`.substring(1)))}}))};I(L),h.config();const C=e=>u.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),A=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),N=e=>u.enum([...e,""]).transform((e=>""!==e?e:void 0)),P=()=>u.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),H=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),D=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(R.core),HIGHCHARTS_MODULE_SCRIPTS:C(R.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(R.indicators),HIGHCHARTS_FORCE_FETCH:A(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:N(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:N(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:A(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:A(),SERVER_ENABLE:A(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:A(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:A(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:A(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:A(),SERVER_SSL_FORCE:A(),SERVER_SSL_PORT:H(),SERVER_SSL_CERT_PATH:P(),POOL_MIN_WORKERS:$(),POOL_MAX_WORKERS:$(),POOL_WORK_LIMIT:H(),POOL_ACQUIRE_TIMEOUT:$(),POOL_CREATE_TIMEOUT:$(),POOL_DESTROY_TIMEOUT:$(),POOL_IDLE_TIMEOUT:$(),POOL_CREATE_RETRY_INTERVAL:$(),POOL_REAPER_INTERVAL:$(),POOL_BENCHMARKING:A(),LOGGING_LEVEL:u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:P(),LOGGING_DEST:P(),UI_ENABLE:A(),UI_ROUTE:P(),OTHER_NODE_ENV:N(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:A(),OTHER_NO_LOGO:A(),OTHER_HARD_RESET_PAGE:A(),DEBUG_ENABLE:A(),DEBUG_HEADLESS:A(),DEBUG_DEVTOOLS:A(),DEBUG_LISTEN_TO_CONSOLE:A(),DEBUG_DUMPIO:A(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),U=["red","yellow","blue","gray","green"];let G={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:U[0]},{title:"warning",color:U[1]},{title:"notice",color:U[2]},{title:"verbose",color:U[3]},{title:"benchmark",color:U[4]}],listeners:[]};for(const[e,t]of Object.entries(L.logging))G[e]=t.value;const j=(o,i)=>{G.toFile&&(G.pathCreated||(!e(G.dest)&&t(G.dest),G.pathCreated=!0),r(`${G.dest}${G.file}`,[i].concat(o).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),G.toFile=!1)})))},M=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=G;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;G.listeners.forEach((e=>{e(s,r.join(" "))})),G.toConsole&&console.log.apply(void 0,[s.toString()[G.levelsDesc[t-1].color]].concat(r)),j(r,s)},F=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=G;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];G.toConsole&&console.log.apply(void 0,[n.toString()[G.levelsDesc[e-1].color]].concat([o[U[e-1]],"\n",a])),G.listeners.forEach((e=>{e(n,l.join(" "))})),j(l,n)},W=e=>{e>=0&&e<=G.levelsDesc.length&&(G.level=e)},V=(e,t)=>{if(G={...G,dest:e||G.dest,file:t||G.file,toFile:!0},0===G.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");G.dest.endsWith("/")||(G.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},X=(e=!1,t)=>{const r=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(o(e,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else i=K(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?s||(s=!0):delete i[e];return s?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):M(3,"[cli] No resources found.")};function K(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const J=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=J(e[r]));return t},z=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Y(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(L).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(L[t]))})),console.log("\n")}const Q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Z=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&Z(o(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ee=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let te={};const re=()=>te,oe=(e,t,r=[])=>{const o=J(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:oe(o[e],s,r);var i;return o};function ie(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ie(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function se(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:se(o);return t}function ne(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ne(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ae(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?m:g)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class le extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ce={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},pe=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),he=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),M(4,`[cache] Fetching script - ${e}.js`);const i=await ae(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new le(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return M(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ue=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",n=e.cdnURL||ce.cdnURL;M(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ce.sources=await(async(e,t,r,o,i)=>{let s;const n=o.host,a=o.port;if(n&&a)try{s=new c({host:n,port:a})}catch(e){throw new le("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:D.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...r.map((e=>he(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...e.coreScripts.map((e=>`${n}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${n}maps/${i}modules/${e}`:`${n}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${n}stock/${i}indicators/${e}`))],e.customScripts,t,a),ce.hcVersion=pe(ce),s(r,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async r=>{const{highcharts:i,server:n}=r,l=a(q,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)M(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ue(i,n.proxy,h);else{let e=!1;const t=JSON.parse(o(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:s,indicatorScripts:a}=i,l=r.length+s.length+a.length;t.version!==i.version?(M(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(M(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(s||[]).some((e=>{if(!t.modules[e])return M(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ue(i,n.proxy,h):(M(3,"[cache] Dependency cache is up to date, proceeding."),ce.sources=o(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};ce.activeManifest=r,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,re().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&s(h),Highcharts[t.export.constr||"chart"]("container",c,p);const u=o();for(const e in u)"function"!=typeof u[e]&&delete u[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ye=o(q+"/templates/template.html","utf8");let be;async function we(){if(!be)return!1;const e=await be.newPage();return await e.setCacheEnabled(!1),await Te(e),function(e){const{debug:t}=re();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function Ee(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function Te(e){await e.setContent(ye,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ge()}/sources.js`}),await e.evaluate(fe)}const Se=async(e,t,r,o)=>e.evaluate(ve,t,r,o);var xe=async(e,t,r)=>{let i=[];try{M(4,"[export] Determining export path.");const s=r.export,a=s?.options?.chart?.displayErrors&&ce.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(M(4,"[export] Treating as SVG."),"svg"===s.type)return t;l=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else M(4,"[export] Treating as config."),s.strInj?await Se(e,{chart:{height:s.height,width:s.width}},r,a):(t.chart.height=s.height,t.chart.width=s.width,await Se(e,t,r,a));i=await async function(e,t){const r=[],i=t.customLogic.resources;if(i){const s=[];if(i.js&&s.push({content:i.js}),i.files)for(const e of i.files){const t=!e.startsWith("http");s.push(t?{content:o(e,"utf8")}:{url:e})}for(const t of s)try{r.push(await e.addScriptTag(t))}catch(e){F(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(i.css){let o=i.css.match(/@import\s*([^;]*);/g);if(o)for(let e of o)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?a.push({url:e}):t.customLogic.allowFileResources&&a.push({path:n.join(q,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{r.push(await e.addStyleTag(t))}catch(e){F(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return r}(e,r);const c=l?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.ceil(c.chartHeight||s.height),h=Math.ceil(c.chartWidth||s.width),{x:u,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let g;if(await e.setViewport({height:p,width:h,deviceScaleFactor:l?1:parseFloat(s.scale)}),"svg"===s.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(s.type))g=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new le("Rasterization timeout"))),i||1500)))]))(e,s.type,"base64",{width:h,height:p,x:u,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new le(`[export] Unsupported output format ${s.type}.`);g=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new le("Rasterization timeout"))),i||1500)))])))(e,p,h,"base64",s.rasterizationTimeout)}return await Ee(e,i),g}catch(t){return await Ee(e,i),t}};let Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=v(),r=(new Date).getTime();try{if(e=await we(),!e||e.isClosed())throw new le("The page is invalid or closed.");M(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new le("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Oe.workLimit/2))}},validate:async e=>!(Oe.workLimit&&++e.workCount>Oe.workLimit)||(M(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Oe.workLimit}).`),!1),destroy:async e=>{M(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},ke=async e=>{if(Oe=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=re().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!be){let e=0;const r=async()=>{try{M(3,`[browser] Attempting to get a browser instance (try ${++e}).`),be=await y.launch(o)}catch(t){if(F(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;M(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&M(3,"[browser] Launched browser in debug mode.")}catch(e){throw new le("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!be)throw new le("[browser] Cannot find a browser to open.")}return be}(e.puppeteerArgs),M(3,`[pool] Initializing pool with workers: min ${Oe.minWorkers}, max ${Oe.maxWorkers}.`),Re)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Oe.minWorkers)>parseInt(Oe.maxWorkers)&&(Oe.minWorkers=Oe.maxWorkers);try{Re=new f({..._e,min:parseInt(Oe.minWorkers),max:parseInt(Oe.maxWorkers),acquireTimeoutMillis:Oe.acquireTimeout,createTimeoutMillis:Oe.createTimeout,destroyTimeoutMillis:Oe.destroyTimeout,idleTimeoutMillis:Oe.idleTimeout,createRetryIntervalMillis:Oe.createRetryInterval,reapIntervalMillis:Oe.reaperInterval,propagateCreateError:!1}),Re.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){F(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),M(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Re.on("destroySuccess",((e,t)=>{M(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Re.release(e)})),M(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new le("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(M(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),M(4,"[browser] Destroyed the pool of resources."))}await async function(){be?.connected&&await be.close(),M(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let r;try{if(M(4,"[pool] Work received, starting to process."),++Le.exportAttempts,Oe.benchmarking&&Ne(),!Re)throw new le("Work received, but pool has not been started.");const o=ee();try{M(4,"[pool] Acquiring a worker handle."),r=await Re.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!r.page)throw new le("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();M(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=ee(),n=await xe(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await we()),new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Re.release(r);const a=(new Date).getTime()-i;return Le.timeSpent+=a,Le.spentAverage=Le.timeSpent/++Le.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Le.droppedExports,r&&Re.release(r),new le(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ne(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ae();M(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),M(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),M(5,`[pool] The number of all created resources: ${r}.`),M(5,`[pool] The number of available resources: ${o}.`),M(5,`[pool] The number of acquired resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Pe=Ae,He=()=>Le;let $e=!1;const De=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=J(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=oe(t,e,_),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,re()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{M(4,"[chart] Attempting to export from a SVG input.");const e=Me(function(e){const t=new b("").window;return w(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++Le.exportFromSvgAttempts,e}catch(e){return t(new le("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return M(4,"[chart] Attempting to export from an input file."),r.export.instr=o(i.infile,"utf8"),Me(r.export.instr.trim(),r,t)}catch(e){return t(new le("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return M(4,"[chart] Attempting to export from a raw input."),Q(r.customLogic?.allowCodeExecution)?je(r,t):"string"==typeof i.instr?Me(i.instr.trim(),r,t):Ge(r,i.instr||i.options,t)}catch(e){return t(new le("[chart] Error loading raw input.").setError(e))}return t(new le("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||K(e.export?.instr),o=K(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const s={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ge=async(e,t,r,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:$e;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=X(e.customLogic.resources,Q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=o("resources.json","utf8");e.customLogic.resources=X(t,Q(e.customLogic.allowFileResources))}catch(e){F(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new le("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=B(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=K(o(s[e],"utf8"),!0):s[e]=K(s[e],!0))}catch(t){s[e]={},F(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Z(n.customCode,n.allowFileResources)}catch(e){F(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=o(n.callback,"utf8")}catch(e){n.callback=!1,F(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ue(e)};try{return r(!1,await Ce(s.strInj||t||i,e))}catch(e){return r(e)}},je=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=z(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ge(e,!1,t)}catch(r){return t(new le(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},Me=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ge(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ge(t,o,r)}catch(e){return Q(o)?je(t,r):r(new le("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Fe=[],We=()=>{M(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},Ve=(e,t,r,o)=>{F(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},qe=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Be=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=x({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Xe extends le{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Ke=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Xe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Xe("No new version supplied.",400);try{await(async e=>{const t=re();t?.highcharts&&(t.highcharts.version=e),await de(t)})(i)}catch(e){throw new Xe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const Je={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Ye=[],Qe=[],Ze=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},et=async(e,t,r)=>{try{const r=ee(),i=v().replace(/-/g,""),s=re(),n=e.body,a=++ze;let l=B(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=K(n.infile||n.options||n.data);if(!c&&!n.svg)throw M(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Xe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let p=!1;if(p=Ze(Ye,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),M(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:K(n.globalOptions,!0),themeOptions:K(n.themeOptions,!0)},customLogic:{allowCodeExecution:$e,allowFileResources:!1,resources:K(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=z(c,u.customLogic.allowCodeExecution));const d=oe(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new Xe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await De(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return M(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Ze(Qe,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Je[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const tt=JSON.parse(o(a(q,"package.json"))),rt=new Date,ot=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ot.push(t),ot.length>30&&ot.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=He(),o=ot.length,i=ot.reduce(((e,t)=>e+t),0)/ot.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:rt,uptime:Math.floor(((new Date).getTime()-rt.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const st=new Map,nt=T();nt.disable("x-powered-by"),nt.use(E());const at=S.memoryStorage(),lt=S({storage:at,limits:{fieldSize:52428800}});nt.use(T.json({limit:52428800})),nt.use(T.urlencoded({extended:!0,limit:52428800})),nt.use(lt.none());const ct=e=>{e.on("clientError",(e=>{F(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{F(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{F(1,e,`[server] Socket error: ${e.message}`)}))}))},pt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=g.createServer(nt);ct(t),t.listen(e.port,e.host),st.set(e.port,t),M(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await i.readFile(l.join(e.ssl.certPath,"server.key"),"utf8"),r=await i.readFile(l.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){M(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=m.createServer({key:t,cert:r},nt);ct(o),o.listen(e.ssl.port,e.host),st.set(e.ssl.port,o),M(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Be(nt,e.rateLimiting),nt.use(T.static(l.join(q,"public"))),it(nt),(e=>{e.post("/",et),e.post("/:filename",et)})(nt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(q,"public","index.html"))}))})(nt),Ke(nt),(e=>{e.use(Ve),e.use(qe)})(nt)}catch(e){throw new le("[server] Could not configure and start the server.").setError(e)}},ht=()=>{M(4,"[server] Closing all servers.");for(const[e,t]of st)t.close((()=>{st.delete(e),M(4,`[server] Closed server on port: ${e}.`)}))};var ut={startServer:pt,closeServers:ht,getServers:()=>st,enableRateLimiting:e=>Be(nt,e),getExpress:()=>T,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const dt=async e=>{await Promise.allSettled([We(),ht(),Ie()]),process.exit(e)};var gt={server:ut,startServer:pt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,$e=Q(t),(e=>{W(e&&parseInt(e.level)),e&&e.dest&&V(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(M(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{M(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await dt(0)})),process.on("SIGTERM",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await dt(0)})),process.on("SIGHUP",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await dt(0)})),process.on("uncaughtException",(async(e,t)=>{F(1,e,`The ${t} error.`),await dt(1)}))),await de(e),await ke({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await De(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;s(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await Ie()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(De({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await Ie()}catch(e){throw new le("[chart] Error encountered during batch export.").setError(e)}},startExport:De,initPool:ke,killPool:Ie,setOptions:(e,t)=>(t?.length&&(te=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(o(r))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ie(L,te),te=se(L),e&&(te=oe(te,e,_)),t?.length&&(te=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=Q(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Y();return e}(te,t,L)),te),shutdownCleanUp:dt,log:M,logWithStack:F,setLogLevel:W,enableFileLogging:V,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=k[r]?k[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e(t)&&(r=JSON.parse(o(t,"utf8")));const s=Object.keys(O).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:s},{onSubmit:async(e,o)=>{let s=0,n=[];for(const e of o)O[e]=O[e].map((t=>({...t,section:e}))),n=[...n,...O[e]];return await p(n,{onSubmit:async(e,o)=>{if("moduleScripts"===e.name?(o=o.length?o.map((t=>e.choices[t])):e.choices,r[e.section][e.name]=o):r[e.section]=ne(Object.assign({},r[e.section]||{}),e.name.split("."),e.choices?e.choices[o]:o),++s===n.length){try{await i.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){F(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(o(a(q,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(o(q+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Y};export{gt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index ebc98c8b..b14a474e 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/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache: () => cache,\r\n highcharts: () => cache.sources,\r\n version: () => cache.hcVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport fs from 'fs';\r\nimport * as url from 'url';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\r\nconst template = fs.readFileSync(\r\n __dirname + '/../templates/template.html',\r\n 'utf8'\r\n);\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__basedir, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n const { debug } = getOptions();\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport cache from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","fs","browser","newPage","page","setCacheEnabled","setPageContent","setContent","waitUntil","addScriptTag","path","evaluate","__basedir","setAsConfig","puppeteerExport","injectedResources","clearInjected","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","$eval","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","errorMessage","innerHTML","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","browserClose","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"mnBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport const getCache = () => cache;\r\n\r\nexport const highcharts = () => cache.sources;\r\n\r\nexport const version = () => cache.hcVersion;\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache,\r\n highcharts,\r\n version\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport async function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n // Set page events\r\n setPageEvents(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to which resources will be\r\n * added.\r\n * @param {Object} options - All options and configuration.\r\n *\r\n * @returns {Promise>} - Promise resolving to an array of injected\r\n * resources.\r\n */\r\nexport async function addPageResources(page, options) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\r\n * injected resources and resets CSS and script tags on the page. Additionally,\r\n * it destroys previously existing charts.\r\n *\r\n * @param {Object} page - The Puppeteer Page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events for a Puppeteer Page.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to set events to.\r\n */\r\nfunction setPageEvents(page) {\r\n // Get debug options\r\n const { debug } = getOptions();\r\n\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { getCache } from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = async (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n // Injected resources array (additional JS and CSS)\r\n let injectedResources = [];\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources = await addPageResources(page, options);\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // Rasterization process\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return data;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n create as createBrowser,\r\n close as closeBrowser,\r\n newPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await newPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await newPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { updateVersion, version } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport { version } from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","isClosed","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","closeBrowser","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","vSwitchRoute","post","adminToken","token","newVersion","params","updateVersion","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","sendFile","uiRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"0lBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file diff --git a/lib/browser.js b/lib/browser.js index 2533caa7..6c4d9d40 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -12,8 +12,8 @@ See LICENSE file in root for details. *******************************************************************************/ -import fs from 'fs'; -import * as url from 'url'; +import { readFileSync } from 'fs'; +import path from 'path'; import puppeteer from 'puppeteer'; @@ -21,15 +21,12 @@ import { getCachePath } from './cache.js'; import { getOptions } from './config.js'; import { setupHighcharts } from './highcharts.js'; import { log, logWithStack } from './logger.js'; +import { __dirname } from './utils.js'; import ExportError from './errors/ExportError.js'; // Get the template for the page -const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); -const template = fs.readFileSync( - __dirname + '/../templates/template.html', - 'utf8' -); +const template = readFileSync(__dirname + '/templates/template.html', 'utf8'); let browser; @@ -164,6 +161,9 @@ export async function newPage() { // Set the content await setPageContent(page); + // Set page events + setPageEvents(page); + return page; } @@ -204,6 +204,161 @@ export async function clearPage(page, hardReset = false) { } } +/** + * Adds custom JS and CSS resources to a Puppeteer Page based on the specified + * options. + * + * @param {Object} page - The Puppeteer Page object to which resources will be + * added. + * @param {Object} options - All options and configuration. + * + * @returns {Promise>} - Promise resolving to an array of injected + * resources. + */ +export async function addPageResources(page, options) { + // Injected resources array + const injectedResources = []; + + // Use resources + const resources = options.customLogic.resources; + if (resources) { + const injectedJs = []; + + // Load custom JS code + if (resources.js) { + injectedJs.push({ + content: resources.js + }); + } + + // Load scripts from all custom files + if (resources.files) { + for (const file of resources.files) { + const isLocal = !file.startsWith('http') ? true : false; + + // Add each custom script from resources' files + injectedJs.push( + isLocal + ? { + content: readFileSync(file, 'utf8') + } + : { + url: file + } + ); + } + } + + for (const jsResource of injectedJs) { + try { + injectedResources.push(await page.addScriptTag(jsResource)); + } catch (error) { + logWithStack(2, error, `[export] The JS resource cannot be loaded.`); + } + } + injectedJs.length = 0; + + // Load CSS + const injectedCss = []; + if (resources.css) { + let cssImports = resources.css.match(/@import\s*([^;]*);/g); + if (cssImports) { + // Handle css section + for (let cssImportPath of cssImports) { + if (cssImportPath) { + cssImportPath = cssImportPath + .replace('url(', '') + .replace('@import', '') + .replace(/"/g, '') + .replace(/'/g, '') + .replace(/;/, '') + .replace(/\)/g, '') + .trim(); + + // Add each custom css from resources + if (cssImportPath.startsWith('http')) { + injectedCss.push({ + url: cssImportPath + }); + } else if (options.customLogic.allowFileResources) { + injectedCss.push({ + path: path.join(__dirname, cssImportPath) + }); + } + } + } + } + + // The rest of the CSS section will be content by now + injectedCss.push({ + content: resources.css.replace(/@import\s*([^;]*);/g, '') || ' ' + }); + + for (const cssResource of injectedCss) { + try { + injectedResources.push(await page.addStyleTag(cssResource)); + } catch (error) { + logWithStack(2, error, `[export] The CSS resource cannot be loaded.`); + } + } + injectedCss.length = 0; + } + } + return injectedResources; +} + +/** + * Clears out all state set on the page with addScriptTag/addStyleTag. Removes + * injected resources and resets CSS and script tags on the page. Additionally, + * it destroys previously existing charts. + * + * @param {Object} page - The Puppeteer Page object from which resources will + * be cleared. + * @param {Array} injectedResources - Array of injected resources + * to be cleared. + */ +export async function clearPageResources(page, injectedResources) { + for (const resource of injectedResources) { + await resource.dispose(); + } + + // Destroy old charts after export is done and reset all CSS and script tags + await page.evaluate(() => { + // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG + // exports + if (typeof Highcharts !== 'undefined') { + // eslint-disable-next-line no-undef + const oldCharts = Highcharts.charts; + + // Check in any already existing charts + if (Array.isArray(oldCharts) && oldCharts.length) { + // Destroy old charts + for (const oldChart of oldCharts) { + oldChart && oldChart.destroy(); + // eslint-disable-next-line no-undef + Highcharts.charts.shift(); + } + } + } + + // eslint-disable-next-line no-undef + const [...scriptsToRemove] = document.getElementsByTagName('script'); + // eslint-disable-next-line no-undef + const [, ...stylesToRemove] = document.getElementsByTagName('style'); + // eslint-disable-next-line no-undef + const [...linksToRemove] = document.getElementsByTagName('link'); + + // Remove tags + for (const element of [ + ...scriptsToRemove, + ...stylesToRemove, + ...linksToRemove + ]) { + element.remove(); + } + }); +} + /** * Sets the content for a Puppeteer Page using a predefined template * and additional scripts. Also, sets the pageerror in order to catch @@ -222,10 +377,45 @@ async function setPageContent(page) { await page.evaluate(setupHighcharts); } +/** + * Set events for a Puppeteer Page. + * + * @param {Object} page - The Puppeteer Page object to set events to. + */ +function setPageEvents(page) { + // Get debug options + const { debug } = getOptions(); + + // Set the console listener, if needed + if (debug.enable && debug.listenToConsole) { + page.on('console', (message) => { + console.log(`[debug] ${message.text()}`); + }); + } + + // Set the pageerror listener + page.on('pageerror', async (error) => { + // TODO: Consider adding a switch here that turns on log(0) logging + // on page errors. + await page.$eval( + '#container', + (element, errorMessage) => { + // eslint-disable-next-line no-undef + if (window._displayErrors) { + element.innerHTML = errorMessage; + } + }, + `

Chart input data error:

${error.toString()}` + ); + }); +} + export default { get, create, close, newPage, - clearPage + clearPage, + addPageResources, + clearPageResources }; diff --git a/lib/cache.js b/lib/cache.js index 2a2522f9..cd712a15 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -390,11 +390,17 @@ export const checkAndUpdateCache = async (options) => { export const getCachePath = () => join(__dirname, getOptions().highcharts.cachePath); +export const getCache = () => cache; + +export const highcharts = () => cache.sources; + +export const version = () => cache.hcVersion; + export default { checkAndUpdateCache, getCachePath, updateVersion, - getCache: () => cache, - highcharts: () => cache.sources, - version: () => cache.hcVersion + getCache, + highcharts, + version }; diff --git a/lib/export.js b/lib/export.js index cc808a25..5ccd8629 100644 --- a/lib/export.js +++ b/lib/export.js @@ -12,19 +12,15 @@ See LICENSE file in root for details. *******************************************************************************/ -import { readFileSync } from 'fs'; -import path from 'path'; -import * as url from 'url'; - -import cache from './cache.js'; +import { addPageResources, clearPageResources } from './browser.js'; +import { getCache } from './cache.js'; import { triggerExport } from './highcharts.js'; -import { log, logWithStack } from './logger.js'; +import { log } from './logger.js'; + import svgTemplate from './../templates/svg_export/svg_export.js'; import ExportError from './errors/ExportError.js'; -const __basedir = url.fileURLToPath(new URL('.', import.meta.url)); - /** * Retrieves the clipping region coordinates of the specified page element with * the id 'chart-container'. @@ -138,7 +134,7 @@ const createSVG = (page) => * * @returns {Promise} Promise resolving after the configuration is set. */ -const setAsConfig = (page, chart, options, displayErrors) => +const setAsConfig = async (page, chart, options, displayErrors) => page.evaluate(triggerExport, chart, options, displayErrors); /** @@ -152,55 +148,8 @@ const setAsConfig = (page, chart, options, displayErrors) => * the exported data or rejecting with an ExportError. */ export default async (page, chart, options) => { - /** - * Keeps track of all resources added on the page with addXXXTag. etc - * It's VITAL that all added resources ends up here so we can clear things - * out when doing a new export in the same page! - */ - const injectedResources = []; - - /** Clear out all state set on the page with addScriptTag/addStyleTag. */ - const clearInjected = async (page) => { - for (const resource of injectedResources) { - await resource.dispose(); - } - - // Destroy old charts after export is done and reset all CSS and script tags - await page.evaluate(() => { - // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG - // exports - if (typeof Highcharts !== 'undefined') { - // eslint-disable-next-line no-undef - const oldCharts = Highcharts.charts; - - // Check in any already existing charts - if (Array.isArray(oldCharts) && oldCharts.length) { - // Destroy old charts - for (const oldChart of oldCharts) { - oldChart && oldChart.destroy(); - // eslint-disable-next-line no-undef - Highcharts.charts.shift(); - } - } - } - - // eslint-disable-next-line no-undef - const [...scriptsToRemove] = document.getElementsByTagName('script'); - // eslint-disable-next-line no-undef - const [, ...stylesToRemove] = document.getElementsByTagName('style'); - // eslint-disable-next-line no-undef - const [...linksToRemove] = document.getElementsByTagName('link'); - - // Remove tags - for (const element of [ - ...scriptsToRemove, - ...stylesToRemove, - ...linksToRemove - ]) { - element.remove(); - } - }); - }; + // Injected resources array (additional JS and CSS) + let injectedResources = []; try { log(4, '[export] Determining export path.'); @@ -210,7 +159,7 @@ export default async (page, chart, options) => { // Decide whether display error or debbuger wrapper around it const displayErrors = exportOptions?.options?.chart?.displayErrors && - cache.getCache().activeManifest.modules.debugger; + getCache().activeManifest.modules.debugger; let isSVG; if ( @@ -256,95 +205,10 @@ export default async (page, chart, options) => { } } - // Use resources - const resources = options.customLogic.resources; - if (resources) { - const injectedJs = []; - - // Load custom JS code - if (resources.js) { - injectedJs.push({ - content: resources.js - }); - } - - // Load scripts from all custom files - if (resources.files) { - for (const file of resources.files) { - const isLocal = !file.startsWith('http') ? true : false; - - // Add each custom script from resources' files - injectedJs.push( - isLocal - ? { - content: readFileSync(file, 'utf8') - } - : { - url: file - } - ); - } - } - - for (const jsResource of injectedJs) { - try { - injectedResources.push(await page.addScriptTag(jsResource)); - } catch (error) { - logWithStack(2, error, `[export] The JS resource cannot be loaded.`); - } - } - injectedJs.length = 0; - - // Load CSS - const injectedCss = []; - if (resources.css) { - let cssImports = resources.css.match(/@import\s*([^;]*);/g); - if (cssImports) { - // Handle css section - for (let cssImportPath of cssImports) { - if (cssImportPath) { - cssImportPath = cssImportPath - .replace('url(', '') - .replace('@import', '') - .replace(/"/g, '') - .replace(/'/g, '') - .replace(/;/, '') - .replace(/\)/g, '') - .trim(); - - // Add each custom css from resources - if (cssImportPath.startsWith('http')) { - injectedCss.push({ - url: cssImportPath - }); - } else if (options.customLogic.allowFileResources) { - injectedCss.push({ - path: path.join(__basedir, cssImportPath) - }); - } - } - } - } - - // The rest of the CSS section will be content by now - injectedCss.push({ - content: resources.css.replace(/@import\s*([^;]*);/g, '') || ' ' - }); - - for (const cssResource of injectedCss) { - try { - injectedResources.push(await page.addStyleTag(cssResource)); - } catch (error) { - logWithStack( - 2, - error, - `[export] The CSS resource cannot be loaded.` - ); - } - } - injectedCss.length = 0; - } - } + // Keeps track of all resources added on the page with addXXXTag. etc + // It's VITAL that all added resources ends up here so we can clear things + // out when doing a new export in the same page! + injectedResources = await addPageResources(page, options); // Get the real chart size and set the zoom accordingly const size = isSVG @@ -401,7 +265,7 @@ export default async (page, chart, options) => { }); let data; - // RASTERIZATION + // Rasterization process if (exportOptions.type === 'svg') { // SVG data = await createSVG(page); @@ -434,10 +298,11 @@ export default async (page, chart, options) => { ); } - await clearInjected(page); + // Clear previously injected JS and CSS resources + await clearPageResources(page, injectedResources); return data; } catch (error) { - await clearInjected(page); + await clearPageResources(page, injectedResources); return error; } }; diff --git a/lib/highcharts.js b/lib/highcharts.js index 6ba92066..76afd976 100644 --- a/lib/highcharts.js +++ b/lib/highcharts.js @@ -30,7 +30,7 @@ export function setupHighcharts() { * @param {object} options - The export options. * @param {boolean} displayErrors - A flag indicating whether to display errors. */ -export function triggerExport(chartOptions, options, displayErrors) { +export async function triggerExport(chartOptions, options, displayErrors) { // Display errors flag taken from chart options nad debugger module window._displayErrors = displayErrors; diff --git a/lib/pool.js b/lib/pool.js index dc20a83f..6a875a5e 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -16,12 +16,11 @@ import { Pool } from 'tarn'; import { v4 as uuid } from 'uuid'; import { - close as browserClose, create as createBrowser, - newPage as browserNewPage, + close as closeBrowser, + newPage, clearPage } from './browser.js'; -import { getOptions } from './config.js'; import puppeteerExport from './export.js'; import { log, logWithStack } from './logger.js'; import { measureTime } from './utils.js'; @@ -60,7 +59,7 @@ const factory = { const startDate = new Date().getTime(); try { - page = await browserNewPage(); + page = await newPage(); if (!page || page.isClosed()) { throw new ExportError('The page is invalid or closed.'); @@ -78,30 +77,6 @@ const factory = { ).setError(error); } - const { debug } = getOptions(); - // Set the console listener, if needed - if (debug.enable && debug.listenToConsole) { - page.on('console', (message) => { - console.log(`[debug] ${message.text()}`); - }); - } - - // Set the pageerror listener - page.on('pageerror', async (error) => { - // TODO: Consider adding a switch here that turns on log(0) logging - // on page errors. - await page.$eval( - '#container', - (element, errorMessage) => { - // eslint-disable-next-line no-undef - if (window._displayErrors) { - element.innerHTML = errorMessage; - } - }, - `

Chart input data error:

${error.toString()}` - ); - }); - return { id, page, @@ -259,7 +234,7 @@ export async function killPool() { } // Close the browser instance - await browserClose(); + await closeBrowser(); } /** @@ -336,7 +311,7 @@ export const postWork = async (chart, options) => { // 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. if (result.message === 'Rasterization timeout') { workerHandle.page.close(); - workerHandle.page = await browserNewPage(); + workerHandle.page = await newPage(); } throw new ExportError( diff --git a/lib/server/routes/change_hc_version.js b/lib/server/routes/change_hc_version.js index 02b0dfb4..df72049e 100644 --- a/lib/server/routes/change_hc_version.js +++ b/lib/server/routes/change_hc_version.js @@ -12,7 +12,7 @@ See LICENSE file in root for details. *******************************************************************************/ -import cache from '../../cache.js'; +import { updateVersion, version } from '../../cache.js'; import { envs } from '../../envs.js'; import HttpError from '../../errors/HttpError.js'; @@ -54,7 +54,7 @@ export default (app) => if (newVersion) { try { // eslint-disable-next-line import/no-named-as-default-member - await cache.updateVersion(newVersion); + await updateVersion(newVersion); } catch (error) { throw new HttpError( `Version change: ${error.message}`, @@ -65,7 +65,7 @@ export default (app) => // Success response.status(200).send({ statusCode: 200, - version: cache.version(), + version: version(), message: `Successfully updated Highcharts to version: ${newVersion}.` }); } else { diff --git a/lib/server/routes/health.js b/lib/server/routes/health.js index ab9adf11..c6defa26 100644 --- a/lib/server/routes/health.js +++ b/lib/server/routes/health.js @@ -16,7 +16,7 @@ import { readFileSync } from 'fs'; import { join as pather } from 'path'; import { log } from '../../logger.js'; -import cache from '../../cache.js'; +import { version } from '../../cache.js'; import { addInterval } from '../../intervals.js'; import pool from '../../pool.js'; import { __dirname } from '../../utils.js'; @@ -88,7 +88,7 @@ export default function addHealthRoutes(app) { (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60 ) + ' minutes', version: pkgFile.version, - highchartsVersion: cache.version(), + highchartsVersion: version(), averageProcessingTime: stats.spentAverage, performedExports: stats.performedExports, failedExports: stats.droppedExports, diff --git a/package-lock.json b/package-lock.json index df9138b2..9c8b240a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1268,6 +1268,201 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", @@ -1397,9 +1592,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", - "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "devOptional": true, "dependencies": { "undici-types": "~5.26.4" @@ -1441,12 +1636,6 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -2117,9 +2306,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001617", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz", - "integrity": "sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==", + "version": "1.0.30001618", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001618.tgz", + "integrity": "sha512-p407+D1tIkDvsEAPS22lJxLQQaG8OTBEqo0KhzfABGk0TU4juBNDSfH0hyAp/HRyx+M8L17z/ltyhxh27FTfQg==", "dev": true, "funding": [ { @@ -2786,9 +2975,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.762", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.762.tgz", - "integrity": "sha512-rrFvGweLxPwwSwJOjIopy3Vr+J3cIPtZzuc74bmlvmBIgQO3VYJDvVrlj94iKZ3ukXUH64Ex31hSfRTLqvjYJQ==", + "version": "1.4.767", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.767.tgz", + "integrity": "sha512-nzzHfmQqBss7CE3apQHkHjXW77+8w3ubGCIoEijKCJebPufREaFETgGXWTkh32t259F3Kcq+R8MZdFdOJROgYw==", "dev": true }, "node_modules/emittery": { @@ -3685,6 +3874,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5921,21 +6124,6 @@ "node": ">=4" } }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5958,9 +6146,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", - "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz", + "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -6265,9 +6453,9 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -7639,13 +7827,10 @@ } }, "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, "bin": { "nodetouch": "bin/nodetouch.js" } @@ -7897,9 +8082,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz", - "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -7917,7 +8102,7 @@ ], "dependencies": { "escalade": "^3.1.2", - "picocolors": "^1.0.0" + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" From 7b9188feedefaebf71569f0cfc5bf3cb0e828ed7 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 15 May 2024 12:11:57 +0200 Subject: [PATCH 7/7] Updated Puppeteer version. --- package-lock.json | 22 +++++++++++----------- package.json | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c8b240a..627f1936 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.8.1", + "puppeteer": "^22.8.2", "tarn": "^3.0.2", "uuid": "^9.0.1", "zod": "^3.23.8" @@ -2975,9 +2975,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.767", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.767.tgz", - "integrity": "sha512-nzzHfmQqBss7CE3apQHkHjXW77+8w3ubGCIoEijKCJebPufREaFETgGXWTkh32t259F3Kcq+R8MZdFdOJROgYw==", + "version": "1.4.769", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.769.tgz", + "integrity": "sha512-bZu7p623NEA2rHTc9K1vykl57ektSPQYFFqQir8BOYf6EKOB+yIsbFB9Kpm7Cgt6tsLr9sRkqfqSZUw7LP1XxQ==", "dev": true }, "node_modules/emittery": { @@ -6722,15 +6722,15 @@ } }, "node_modules/puppeteer": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.1.tgz", - "integrity": "sha512-CFgPSKV+iydjO/8/hJVj251Hqp2PLcIa70j6H7sYqkwM8YJ+D3CA74Ufuj+yKtvDIntQPB/nLw4EHrHPcHOPjw==", + "version": "22.8.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.2.tgz", + "integrity": "sha512-yNZmKZHhCtBAjwuzonMyzgXLYxnvR+tbpatuyMffK+zmag84xyqE2EvPEWV1FvDXwW3m+/PT4Zp4KLerWWydQQ==", "hasInstallScript": true, "dependencies": { "@puppeteer/browsers": "2.2.3", "cosmiconfig": "9.0.0", "devtools-protocol": "0.0.1273771", - "puppeteer-core": "22.8.1" + "puppeteer-core": "22.8.2" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -6740,9 +6740,9 @@ } }, "node_modules/puppeteer-core": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.1.tgz", - "integrity": "sha512-m1F6ZSTw1xrJ6xD4B+HonkSNVQmMrRMaqca/ivRcZYJ6jqzOnfEh3QgO9HpNPj6heiAZ2+4IPAU3jdZaTIDnSA==", + "version": "22.8.2", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.2.tgz", + "integrity": "sha512-Gg9jUdJeF+UDbYPhwD602ky1LeS+AXDksl6sludrti1b7Sv/U4ZGY1LFyejarkIBCSHiPWL9SngXKCNcdZWBgQ==", "dependencies": { "@puppeteer/browsers": "2.2.3", "chromium-bidi": "0.5.19", diff --git a/package.json b/package.json index d6c62e8a..0dc66f9e 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "jsdom": "^24.0.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.8.1", + "puppeteer": "^22.8.2", "tarn": "^3.0.2", "uuid": "^9.0.1", "zod": "^3.23.8"